import { OptionsResponseDto } from '../dto/options-response.dto';

/**
 * Transformer class for converting raw option data into the standardized OptionsResponseDto format.
 *
 * This transformer is used to format data for dropdowns, select inputs, autocomplete fields,
 * and any UI component that requires a consistent {value, label} structure.
 *
 * The class provides a simple, reusable way to transform various data sources
 * (database results, API responses, internal data structures) into the
 * standardized option format expected by frontend components.
 *
 * @example
 * // Transform database entities to dropdown options
 * const countries = await countryRepository.find();
 * const transformer = new OptionsTransformer();
 * const countryOptions = transformer.transform(countries);
 * // Returns: [{value: 1, label: 'United States'}, {value: 2, label: 'Canada'}, ...]
 *
 * @example
 * // Transform with custom field mapping
 * const customTransformer = new OptionsTransformer('code', 'displayName');
 * const options = customTransformer.transform(data);
 */
export class OptionsTransformer {
  /**
   * Default field names used for value and label extraction.
   * These can be overridden through constructor parameters for custom mappings.
   */
  private valueField: string;
  private labelField: string;

  /**
   * Creates an instance of OptionsTransformer.
   *
   * @param valueField - Name of the field to use as value (default: 'id')
   * @param labelField - Name of the field to use as label (default: 'name')
   *
   * @example
   * // Use default fields (id, name)
   * const defaultTransformer = new OptionsTransformer();
   *
   * @example
   * // Use custom fields
   * const customTransformer = new OptionsTransformer('code', 'displayName');
   *
   * @example
   * // For database entities with different column names
   * const dbTransformer = new OptionsTransformer('country_id', 'country_name');
   */
  constructor(valueField: string = 'id', labelField: string = 'name') {
    this.valueField = valueField;
    this.labelField = labelField;
  }

  /**
   * Transforms an array of raw option objects into an array of OptionsResponseDto objects.
   *
   * @param options - Array of raw option data (typically from database or API)
   * @returns {OptionsResponseDto[]} Array of transformed option objects
   *
   * @example
   * // Basic transformation with default fields
   * const rawOptions = [
   *   { id: 1, name: 'Admin' },
   *   { id: 2, name: 'User' },
   *   { id: 3, name: 'Guest' }
   * ];
   *
   * const transformed = transformer.transform(rawOptions);
   * // Returns: [
   * //   { value: 1, label: 'Admin' },
   * //   { value: 2, label: 'User' },
   * //   { value: 3, label: 'Guest' }
   * // ]
   *
   * @example
   * // With empty or invalid input
   * transformer.transform(null); // Returns: []
   * transformer.transform([]);   // Returns: []
   * transformer.transform([null, undefined]); // Returns: [{value: undefined, label: undefined}]
   */
  transform(options: any): OptionsResponseDto[] {
    // Handle null, undefined, or non-array input
    if (!options || !Array.isArray(options)) {
      return [];
    }

    // Map each option to the standardized format
    return options.map((option: any) => {
      // Safely extract values with nullish coalescing
      const value = option?.[this.valueField];
      const label = option?.[this.labelField];

      // Create the standardized option object
      const optionsResponse: OptionsResponseDto = {
        value: value,
        label: label,
      };

      return optionsResponse;
    });
  }

  /**
   * Transforms a single option object (non-array input).
   * Useful when you need to transform a single entity to option format.
   *
   * @param option - Single option object to transform
   * @returns {OptionsResponseDto | null} Transformed option or null if input is invalid
   *
   * @example
   * const singleRole = { id: 1, name: 'Administrator' };
   * const option = transformer.transformSingle(singleRole);
   * // Returns: { value: 1, label: 'Administrator' }
   */
  transformSingle(option: any): OptionsResponseDto | null {
    if (!option || typeof option !== 'object') {
      return null;
    }

    return {
      value: option[this.valueField],
      label: option[this.labelField],
    };
  }
}
