/**
 * Unit conversion service wrapper for convert-units library
 * Provides type-safe conversion utilities and metadata
 */

import convert from 'convert-units';
import { tempoMeasure } from './tempo';

export type Measure =
  | 'angle'
  | 'apparentPower'
  | 'area'
  | 'current'
  | 'digital'
  | 'each'
  | 'energy'
  | 'frequency'
  | 'illuminance'
  | 'length'
  | 'mass'
  | 'pace'
  | 'partsPer'
  | 'power'
  | 'pressure'
  | 'reactiveEnergy'
  | 'reactivePower'
  | 'speed'
  | 'temperature'
  | 'tempo'
  | 'time'
  | 'voltage'
  | 'volume'
  | 'volumeFlowRate';

export interface UnitInfo {
  abbr: string;
  measure: Measure;
  system: 'metric' | 'imperial' | 'bits' | 'bytes' | string;
  singular: string;
  plural: string;
}

export interface ConversionResult {
  value: number;
  unit: string;
  unitInfo: UnitInfo;
}

/**
 * Get all available measures/categories
 */
export function getAllMeasures(): Measure[] {
  const standardMeasures = convert().measures() as Measure[];
  return [...standardMeasures, 'tempo'];
}

/**
 * Get all units for a specific measure
 */
export function getUnitsForMeasure(measure: Measure): string[] {
  if (measure === 'tempo') {
    return Object.keys(tempoMeasure.tempo.systems.metric);
  }
  return convert().possibilities(measure);
}

/**
 * Get detailed information about a unit
 */
export function getUnitInfo(unit: string): UnitInfo | null {
  try {
    // Check if it's a tempo unit
    const tempoUnits = tempoMeasure.tempo.systems.metric;
    if (unit in tempoUnits) {
      const tempoUnit = tempoUnits[unit as keyof typeof tempoUnits];
      return {
        abbr: unit,
        measure: 'tempo',
        system: 'metric',
        singular: tempoUnit.name.singular,
        plural: tempoUnit.name.plural,
      };
    }

    const description = convert().describe(unit);
    return description as UnitInfo;
  } catch {
    return null;
  }
}

/**
 * Convert a value from one unit to another
 */
export function convertUnit(
  value: number,
  fromUnit: string,
  toUnit: string
): number {
  try {
    // Handle tempo conversions
    const tempoUnits = tempoMeasure.tempo.systems.metric;
    const isFromTempo = fromUnit in tempoUnits;
    const isToTempo = toUnit in tempoUnits;

    if (isFromTempo && isToTempo) {
      // Same unit - no conversion needed
      if (fromUnit === toUnit) {
        return value;
      }

      const fromAnchor = tempoUnits[fromUnit as keyof typeof tempoUnits].to_anchor;
      const toAnchor = tempoUnits[toUnit as keyof typeof tempoUnits].to_anchor;

      // Special handling for BPM conversions (reciprocal relationship)
      if (fromUnit === 'BPM') {
        // BPM → time unit: divide anchor by BPM value
        // Example: 120 BPM → quarter = 60000 / 120 = 500ms
        return toAnchor / value;
      } else if (toUnit === 'BPM') {
        // Time unit → BPM: divide anchor by time value
        // Example: 500ms quarter → BPM = 60000 / 500 = 120
        return fromAnchor / value;
      } else {
        // Time unit → time unit: convert through BPM
        // Example: 500ms quarter → eighth
        // Step 1: 500ms → BPM = 60000 / 500 = 120
        // Step 2: 120 BPM → eighth = 30000 / 120 = 250ms
        const bpm = fromAnchor / value;
        return toAnchor / bpm;
      }
    }

    return convert(value).from(fromUnit).to(toUnit);
  } catch (error) {
    console.error('Conversion error:', error);
    return value;
  }
}

/**
 * Convert a value to all compatible units in the same measure
 */
export function convertToAll(
  value: number,
  fromUnit: string
): ConversionResult[] {
  try {
    const unitInfo = getUnitInfo(fromUnit);
    if (!unitInfo) return [];

    const compatibleUnits = getUnitsForMeasure(unitInfo.measure);

    return compatibleUnits.map(toUnit => {
      const convertedValue = convertUnit(value, fromUnit, toUnit);
      const toUnitInfo = getUnitInfo(toUnit);

      return {
        value: convertedValue,
        unit: toUnit,
        unitInfo: toUnitInfo!,
      };
    });
  } catch (error) {
    console.error('Conversion error:', error);
    return [];
  }
}

/**
 * Get category color for a measure (Tailwind class name)
 */
export function getCategoryColor(measure: Measure): string {
  const colorMap: Record<Measure, string> = {
    angle: 'category-angle',
    apparentPower: 'category-apparent-power',
    area: 'category-area',
    current: 'category-current',
    digital: 'category-digital',
    each: 'category-each',
    energy: 'category-energy',
    frequency: 'category-frequency',
    illuminance: 'category-illuminance',
    length: 'category-length',
    mass: 'category-mass',
    pace: 'category-pace',
    partsPer: 'category-parts-per',
    power: 'category-power',
    pressure: 'category-pressure',
    reactiveEnergy: 'category-reactive-energy',
    reactivePower: 'category-reactive-power',
    speed: 'category-speed',
    temperature: 'category-temperature',
    tempo: 'category-tempo',
    time: 'category-time',
    voltage: 'category-voltage',
    volume: 'category-volume',
    volumeFlowRate: 'category-volume-flow-rate',
  };

  return colorMap[measure];
}

/**
 * Get category color hex value for a measure
 */
export function getCategoryColorHex(measure: Measure): string {
  const colorMap: Record<Measure, string> = {
    angle: '#f43f5e',          // Rose 500
    apparentPower: '#8b5cf6',  // Violet 500
    area: '#10b981',           // Emerald 500
    current: '#f59e0b',        // Amber 500
    digital: '#3b82f6',        // Blue 500
    each: '#64748b',           // Slate 500
    energy: '#f59e0b',         // Amber 500
    frequency: '#8b5cf6',      // Violet 500
    illuminance: '#eab308',    // Yellow 500
    length: '#3b82f6',         // Blue 500
    mass: '#10b981',           // Emerald 500
    pace: '#14b8a6',           // Teal 500
    partsPer: '#94a3b8',       // Slate 400
    power: '#8b5cf6',          // Violet 500
    pressure: '#6366f1',       // Indigo 500
    reactiveEnergy: '#f59e0b', // Amber 500
    reactivePower: '#8b5cf6',  // Violet 500
    speed: '#14b8a6',          // Teal 500
    temperature: '#ef4444',    // Red 500
    tempo: '#f97316',          // Orange 500
    time: '#6366f1',           // Indigo 500
    voltage: '#f59e0b',        // Amber 500
    volume: '#10b981',         // Emerald 500
    volumeFlowRate: '#10b981', // Emerald 500
  };

  return colorMap[measure];
}

/**
 * Format measure name for display
 */
export function formatMeasureName(measure: Measure): string {
  const nameMap: Record<Measure, string> = {
    angle: 'Angle',
    apparentPower: 'Apparent Power',
    area: 'Area',
    current: 'Current',
    digital: 'Digital Storage',
    each: 'Each',
    energy: 'Energy',
    frequency: 'Frequency',
    illuminance: 'Illuminance',
    length: 'Length',
    mass: 'Mass',
    pace: 'Pace',
    partsPer: 'Parts Per',
    power: 'Power',
    pressure: 'Pressure',
    reactiveEnergy: 'Reactive Energy',
    reactivePower: 'Reactive Power',
    speed: 'Speed',
    temperature: 'Temperature',
    tempo: 'Tempo / BPM',
    time: 'Time',
    voltage: 'Voltage',
    volume: 'Volume',
    volumeFlowRate: 'Volume Flow Rate',
  };

  return nameMap[measure];
}

/**
 * Search units by query string (fuzzy search)
 */
export function searchUnits(query: string): UnitInfo[] {
  if (!query) return [];

  const allMeasures = getAllMeasures();
  const results: UnitInfo[] = [];
  const lowerQuery = query.toLowerCase();

  for (const measure of allMeasures) {
    const units = getUnitsForMeasure(measure);

    for (const unit of units) {
      const info = getUnitInfo(unit);
      if (!info) continue;

      const searchableText = [
        info.abbr,
        info.singular,
        info.plural,
        measure,
        formatMeasureName(measure),
      ]
        .join(' ')
        .toLowerCase();

      if (searchableText.includes(lowerQuery)) {
        results.push(info);
      }
    }
  }

  return results;
}
