/**
 * @ai-summary React context for unit system preferences with backend sync
 * @ai-context Provides unit preferences, conversion functions, and currency symbol throughout the app
 */

import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
import { UnitSystem, UnitPreferences } from './units.types';
import { safeStorage } from '../utils/safe-storage';
import {
  formatDistanceBySystem,
  formatVolumeBySystem,
  formatFuelEfficiencyBySystem,
  formatPriceBySystem,
  convertDistanceBySystem,
  convertVolumeBySystem,
  convertFuelEfficiencyBySystem,
  getDistanceUnit,
  getVolumeUnit,
  getFuelEfficiencyUnit
} from './units.utils';
import { usePreferences, useUpdatePreferences } from '../../features/settings/hooks/usePreferences';
import { useAuth0 } from '@auth0/auth0-react';

interface UnitsContextType {
  unitSystem: UnitSystem;
  setUnitSystem: (system: UnitSystem) => void;
  preferences: UnitPreferences;
  currencySymbol: string;
  currencyCode: string;
  isLoading: boolean;

  // Conversion functions
  convertDistance: (miles: number) => number;
  convertVolume: (gallons: number) => number;
  convertFuelEfficiency: (mpg: number) => number;

  // Formatting functions
  formatDistance: (miles: number, precision?: number) => string;
  formatVolume: (gallons: number, precision?: number) => string;
  formatFuelEfficiency: (mpg: number, precision?: number) => string;
  formatPrice: (pricePerGallon: number, precision?: number) => string;
}

const UnitsContext = createContext<UnitsContextType | undefined>(undefined);

interface UnitsProviderProps {
  children: ReactNode;
  initialSystem?: UnitSystem;
}

// Currency symbol mapping
const getCurrencySymbol = (system: UnitSystem): string => {
  return system === 'metric' ? '\u20AC' : '$'; // EUR or USD
};

const getCurrencyCode = (system: UnitSystem): string => {
  return system === 'metric' ? 'EUR' : 'USD';
};

export const UnitsProvider: React.FC<UnitsProviderProps> = ({
  children,
  initialSystem = 'imperial'
}) => {
  const [unitSystem, setUnitSystemState] = useState<UnitSystem>(initialSystem);
  const [hasInitialized, setHasInitialized] = useState(false);

  const { isAuthenticated } = useAuth0();
  const { data: backendPreferences, isLoading: preferencesLoading } = usePreferences();
  const updatePreferencesMutation = useUpdatePreferences();

  // Load unit preference from localStorage on mount (fallback)
  useEffect(() => {
    if (!hasInitialized) {
      try {
        const stored = safeStorage.getItem('motovaultpro-unit-system');
        if (stored === 'imperial' || stored === 'metric') {
          setUnitSystemState(stored);
        }
      } catch (error) {
        console.warn('[Units] Failed to load unit system preference from storage:', error);
      }
    }
  }, [hasInitialized]);

  // Sync with backend preferences when they load (takes priority over localStorage)
  useEffect(() => {
    if (backendPreferences?.unitSystem && !hasInitialized) {
      setUnitSystemState(backendPreferences.unitSystem);
      // Also update localStorage to keep them in sync
      try {
        safeStorage.setItem('motovaultpro-unit-system', backendPreferences.unitSystem);
      } catch (error) {
        console.warn('[Units] Failed to sync unit system to storage:', error);
      }
      setHasInitialized(true);
    }
  }, [backendPreferences, hasInitialized]);

  // Mark as initialized when not authenticated (localStorage is the source of truth)
  useEffect(() => {
    if (!isAuthenticated && !hasInitialized) {
      setHasInitialized(true);
    }
  }, [isAuthenticated, hasInitialized]);

  // Handle unit system change with backend sync
  const handleSetUnitSystem = useCallback((system: UnitSystem) => {
    setUnitSystemState(system);

    // Always save to localStorage (offline fallback)
    try {
      safeStorage.setItem('motovaultpro-unit-system', system);
    } catch (error) {
      console.warn('[Units] Failed to save unit system preference:', error);
    }

    // Sync to backend if authenticated
    if (isAuthenticated) {
      updatePreferencesMutation.mutate({ unitSystem: system });
    }
  }, [isAuthenticated, updatePreferencesMutation]);

  // Generate preferences object based on current system
  const preferences: UnitPreferences = {
    system: unitSystem,
    distance: getDistanceUnit(unitSystem),
    volume: getVolumeUnit(unitSystem),
    fuelEfficiency: getFuelEfficiencyUnit(unitSystem),
  };

  // Currency based on unit system
  const currencySymbol = getCurrencySymbol(unitSystem);
  const currencyCode = getCurrencyCode(unitSystem);

  // Conversion functions using current unit system
  const convertDistance = useCallback((miles: number) => convertDistanceBySystem(miles, unitSystem), [unitSystem]);
  const convertVolume = useCallback((gallons: number) => convertVolumeBySystem(gallons, unitSystem), [unitSystem]);
  const convertFuelEfficiency = useCallback((mpg: number) => convertFuelEfficiencyBySystem(mpg, unitSystem), [unitSystem]);

  // Formatting functions using current unit system
  const formatDistance = useCallback((miles: number, precision?: number) =>
    formatDistanceBySystem(miles, unitSystem, precision), [unitSystem]);

  const formatVolume = useCallback((gallons: number, precision?: number) =>
    formatVolumeBySystem(gallons, unitSystem, precision), [unitSystem]);

  const formatFuelEfficiency = useCallback((mpg: number, precision?: number) =>
    formatFuelEfficiencyBySystem(mpg, unitSystem, precision), [unitSystem]);

  const formatPrice = useCallback((pricePerGallon: number, precision?: number) =>
    formatPriceBySystem(pricePerGallon, unitSystem, currencyCode, precision), [unitSystem, currencyCode]);

  const value: UnitsContextType = {
    unitSystem,
    setUnitSystem: handleSetUnitSystem,
    preferences,
    currencySymbol,
    currencyCode,
    isLoading: preferencesLoading && isAuthenticated,
    convertDistance,
    convertVolume,
    convertFuelEfficiency,
    formatDistance,
    formatVolume,
    formatFuelEfficiency,
    formatPrice,
  };

  return (
    <UnitsContext.Provider value={value}>
      {children}
    </UnitsContext.Provider>
  );
};

export const useUnits = (): UnitsContextType => {
  const context = useContext(UnitsContext);
  if (context === undefined) {
    throw new Error('useUnits must be used within a UnitsProvider');
  }
  return context;
};
