import { UnitConverter } from '../../../decorators';
import { SchemaNodeType, SchemaOptionsType } from '../../../services/config-bean';
import { IKosDataModel } from '../../core';
import { ConfigPropertyTypes } from '../../types';
/**
 * Unit conversion configuration for KosConfigProperty instances.
 *
 * Defines how configuration property values should be converted between backend
 * storage units (typically SI) and regional display units. The converter enables
 * automatic unit conversion based on device region while maintaining precision.
 *
 * @example Temperature Conversion
 * ```typescript
 * const temperatureConverter: ConfigPropConverter = {
 *   measure: 'temperature',
 *   from: { unit: 'kelvin', system: 'si' }, // Backend storage
 *   to: { system: 'auto' } // Auto-detect regional display
 * };
 * ```
 *
 * @example Volume Conversion with Specific Units
 * ```typescript
 * const volumeConverter: ConfigPropConverter = {
 *   measure: 'volume',
 *   from: { unit: 'liter' }, // Backend in liters
 *   to: { unit: 'fluid-ounce', system: 'imperial' } // Force US fluid ounces
 * };
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export interface ConfigPropConverter {
  /**
   * The physical measure being converted (temperature, volume, pressure, etc.).
   * This helps the system understand what type of conversion to perform.
   */
  measure?: string;

  /**
   * Source unit configuration (typically backend storage units).
   * Defines the unit system and specific unit that values are stored in.
   */
  from?: UnitConverter;

  /**
   * Target unit configuration (display units).
   * Defines how values should be displayed to users, including regional preferences.
   */
  to?: UnitConverter;
}

/**
 * Formatting options for numeric configuration property display values.
 *
 * Supports both static formatting options and dynamic formatting based on unit system.
 * Built on top of the Intl.NumberFormat API for internationalization support.
 *
 * @example Static Formatting Options
 * ```typescript
 * const staticFormatter: FormatOptions = {
 *   style: 'unit',
 *   unit: 'celsius',
 *   maximumFractionDigits: 1
 * };
 * ```
 *
 * @example Dynamic System-Based Formatting
 * ```typescript
 * const dynamicFormatter: FormatOptions = (system: string) => {
 *   if (system === 'imperial') {
 *     return { style: 'unit', unit: 'fahrenheit', maximumFractionDigits: 0 };
 *   }
 *   return { style: 'unit', unit: 'celsius', maximumFractionDigits: 1 };
 * };
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export type FormatOptions =
  | Intl.NumberFormatOptions
  | ((system: string) => Intl.NumberFormatOptions);

/**
 * Option definition for enumerated configuration properties.
 *
 * Represents a single selectable option with a display label and internal value.
 * Used for configuration properties that have predefined valid values.
 *
 * @example Basic Options
 * ```typescript
 * const optionsList: OptionsType[] = [
 *   { label: 'Low Speed', value: 'low' },
 *   { label: 'Medium Speed', value: 'medium' },
 *   { label: 'High Speed', value: 'high' }
 * ];
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export interface OptionsType {
  /** The internal value used by the system */
  value: string;
  /** The human-readable display label */
  label: string;
}

/**
 * Options provider for configuration properties with enumerated values.
 *
 * Can be either a static list of options or a dynamic function that generates
 * options based on the current unit system. Useful for configuration properties
 * that need different option sets based on regional settings.
 *
 * @example Static Options List
 * ```typescript
 * const staticOptions: OptionsExpander = [
 *   { label: 'Automatic', value: 'auto' },
 *   { label: 'Manual', value: 'manual' },
 *   { label: 'Disabled', value: 'disabled' }
 * ];
 * ```
 *
 * @example Dynamic System-Based Options
 * ```typescript
 * const dynamicOptions: OptionsExpander = (system: string, schemaOptions?: string[]) => {
 *   const baseOptions = [
 *     { label: 'Automatic', value: 'auto' },
 *     { label: 'Manual', value: 'manual' }
 *   ];
 *
 *   // Add system-specific options
 *   if (system === 'imperial') {
 *     baseOptions.push({ label: 'Imperial Mode', value: 'imperial' });
 *   } else if (system === 'metric') {
 *     baseOptions.push({ label: 'Metric Mode', value: 'metric' });
 *   }
 *
 *   return baseOptions;
 * };
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export type OptionsExpander =
  | OptionsType[]
  | ((system: string, options?: string[]) => OptionsType[]);

/**
 * Configuration options for KosConfigProperty instances.
 *
 * These options define how individual configuration properties access and display
 * values from the backend configuration system. They specify the configuration path,
 * attribute name, and optional unit conversion and formatting behavior.
 *
 * @example Basic Property Configuration
 * ```typescript
 * const pumpRateOptions: ConfigBeanPropOptions = {
 *   path: 'assembly:core:board:micro:pump:S4',
 *   attribute: 'nominalRate'
 * };
 * ```
 *
 * @example Property with Unit Conversion
 * ```typescript
 * const temperatureOptions: ConfigBeanPropOptions = {
 *   path: 'assembly:core:board:cooling',
 *   attribute: 'targetTemperature',
 *   converter: {
 *     measure: 'temperature',
 *     from: { unit: 'kelvin' },
 *     to: { system: 'auto' }
 *   },
 *   formatter: {
 *     style: 'unit',
 *     maximumFractionDigits: 1
 *   }
 * };
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export interface ConfigBeanPropOptions {
  /**
   * The hierarchical configuration path using colon-separated notation.
   *
   * This path identifies the specific configuration bean that contains
   * the target attribute. Must match the path used by the parent ConfigBeanModel.
   *
   * @example Common Configuration Paths
   * ```typescript
   * // Hardware component configuration
   * path: 'assembly:core:board:micro:pump:S4'
   *
   * // System-level configuration
   * path: 'system:app'
   *
   * // Service configuration
   * path: 'kos:service:CANPumpMgr'
   * ```
   */
  path: string;

  /**
   * The specific attribute name within the configuration bean.
   *
   * This identifies which property within the configuration bean
   * this KosConfigProperty instance should access and manage.
   *
   * @example Attribute Examples
   * ```typescript
   * attribute: 'nominalRate'      // For pump flow rates
   * attribute: 'targetTemperature' // For temperature settings
   * attribute: 'enabled'          // For boolean flags
   * attribute: 'retryCount'       // For numeric counters
   * ```
   */
  attribute: string;

  /**
   * Optional unit conversion configuration.
   *
   * When provided, enables automatic conversion between backend storage units
   * and regional display units. If omitted, no unit conversion is performed.
   *
   * @example Temperature Conversion
   * ```typescript
   * converter: {
   *   from: { unit: 'kelvin', system: 'si' },
   *   to: { system: 'auto' } // Auto-detect regional system
   * }
   * ```
   */
  converter?: { measure?: string; from?: UnitConverter; to?: UnitConverter };

  /**
   * Optional display formatting configuration.
   *
   * Configures how numeric values are formatted for display, including
   * decimal places, units, and locale-specific formatting rules.
   *
   * @example Custom Formatting
   * ```typescript
   * formatter: {
   *   style: 'unit',
   *   unit: 'celsius',
   *   maximumFractionDigits: 1,
   *   minimumFractionDigits: 1
   * }
   * ```
   */
  formatter?: FormatOptions;

  /**
   * Optional predefined options for enumerated properties.
   *
   * Provides a list of valid values for configuration properties that
   * have discrete options rather than continuous values.
   *
   * @example Static Options
   * ```typescript
   * optionsExpander: [
   *   { label: 'Low', value: 'low' },
   *   { label: 'Medium', value: 'medium' },
   *   { label: 'High', value: 'high' }
   * ]
   * ```
   */
  optionsExpander?: OptionsExpander;

  /**
   * Optional custom service base path.
   *
   * When provided, overrides the default configuration service endpoint.
   * Useful for testing, development, or alternative service implementations.
   *
   * @default undefined (uses default KOS configuration service path)
   */
  readonly serviceBasePath?: string;
}

/**
 * Individual configuration property with automatic unit conversion and regional formatting.
 *
 * Provides type-safe access to specific configuration attributes with built-in unit conversion
 * between backend storage units (typically SI) and regional display units.
 *
 * @example Basic Usage
 * ```typescript
 * const pumpRate = KosConfigProperty.create('pump-rate', {
 *   path: 'assembly:core:board:micro:pump:S4',
 *   attribute: 'nominalRate'
 * });
 * ```
 *
 * @kosService core.use-config-property
 * @group KOS Model
 * @category Configuration
 */
export interface KosConfigProperty<
  PropertyType extends ConfigPropertyTypes = ConfigPropertyTypes
> extends ConfigBeanPropOptions,
    IKosDataModel {
  /** Unique identifier for the config property instance */
  id: string;

  /** Optional custom service base path for configuration endpoints */
  serviceBasePath?: string;

  /** The unit of measure for the property after regional conversion (e.g., "°F", "mL/s") */
  readonly unit?: string;

  /** The property value converted to regional units */
  readonly value?: PropertyType;

  /** The raw backend value before any unit conversion (typically SI units) */
  readonly rawValue?: PropertyType;

  /** The property value with appropriate decimal precision for display */
  readonly significantValue?: PropertyType;

  /** The previous value before the last update */
  readonly previousValue?: PropertyType;

  /** Formatted string representation of the value with units and localization */
  readonly displayValue?: string;

  /** Display configuration options from the backend schema */
  readonly displayOptions?: SchemaOptionsType;

  /** Available enumerated options for this property (if applicable) */
  readonly options?: OptionsType[];

  /** The data type of this property as defined in the backend schema */
  readonly schemaType: SchemaNodeType | "enum";

  /** Optional format specifier from the backend schema (e.g., "s", "ml", "drt") */
  readonly schemaFormat?: string;

  /**
   * Updates the property value and persists it to the backend.
   * Automatically handles unit conversion from display units to backend storage units.
   *
   * @param value The new value in display units
   */
  updateProperty: (value: PropertyType | string) => void;
}
