/**
 * ==========================================================================
 * CSS VARIABLE MANAGER
 * ==========================================================================
 * Manages CSS custom properties for dynamic theme switching
 * Maps Material Design 3 palette to existing design system variables
 * ==========================================================================
 */

import { MaterialPalette, CSSVariables } from '../models/hcl.models';
import { PaletteGenerator } from '../core/palette-generator';

export class CSSVariableManager {

  // ==========================================================================
  // VARIABLE MAPPING
  // ==========================================================================

  /**
   * Generate CSS variables from Material Design 3 palette
   * @param palette Material palette
   * @param mode Light or dark mode
   * @returns CSS variables object
   */
  static generateCSSVariables(palette: MaterialPalette, mode: 'light' | 'dark' = 'light'): CSSVariables {
    const variables: CSSVariables = {};

    // ==========================================================================
    // PRIMARY COLORS
    // ==========================================================================
    variables['--color-primary-key'] = palette.primary[40];
    variables['--color-primary'] = PaletteGenerator.getPrimaryTone(palette.primary, 'main', mode);
    variables['--color-on-primary'] = mode === 'light' ? palette.primary[100] : palette.primary[20];
    variables['--color-primary-container'] = PaletteGenerator.getPrimaryTone(palette.primary, 'container', mode);
    variables['--color-on-primary-container'] = PaletteGenerator.getPrimaryTone(palette.primary, 'on-container', mode);
    variables['--color-inverse-primary'] = mode === 'light' ? palette.primary[80] : palette.primary[40];

    // ==========================================================================
    // SECONDARY COLORS
    // ==========================================================================
    variables['--color-secondary-key'] = palette.secondary[40];
    variables['--color-secondary'] = mode === 'light' ? palette.secondary[40] : palette.secondary[80];
    variables['--color-on-secondary'] = mode === 'light' ? palette.secondary[100] : palette.secondary[20];
    variables['--color-secondary-container'] = mode === 'light' ? palette.secondary[90] : palette.secondary[30];
    variables['--color-on-secondary-container'] = mode === 'light' ? palette.secondary[10] : palette.secondary[90];

    // ==========================================================================
    // TERTIARY COLORS
    // ==========================================================================
    variables['--color-tertiary-key'] = palette.tertiary[40];
    variables['--color-tertiary'] = mode === 'light' ? palette.tertiary[40] : palette.tertiary[80];
    variables['--color-on-tertiary'] = mode === 'light' ? palette.tertiary[100] : palette.tertiary[20];
    variables['--color-tertiary-container'] = mode === 'light' ? palette.tertiary[90] : palette.tertiary[30];
    variables['--color-on-tertiary-container'] = mode === 'light' ? palette.tertiary[10] : palette.tertiary[90];

    // ==========================================================================
    // ERROR COLORS
    // ==========================================================================
    variables['--color-error-key'] = palette.error[40];
    variables['--color-error'] = mode === 'light' ? palette.error[40] : palette.error[80];
    variables['--color-on-error'] = mode === 'light' ? palette.error[100] : palette.error[20];
    variables['--color-error-container'] = mode === 'light' ? palette.error[90] : palette.error[30];
    variables['--color-on-error-container'] = mode === 'light' ? palette.error[10] : palette.error[90];

    // ==========================================================================
    // NEUTRAL COLORS
    // ==========================================================================
    variables['--color-neutral-key'] = palette.neutral[10];
    variables['--color-neutral'] = mode === 'light' ? palette.neutral[25] : palette.neutral[80];
    variables['--color-neutral-variant-key'] = palette.neutralVariant[15];
    variables['--color-neutral-variant'] = mode === 'light' ? palette.neutralVariant[30] : palette.neutralVariant[70];

    // ==========================================================================
    // SURFACE COLORS (The most important for your existing system)
    // ==========================================================================
    if (mode === 'light') {
      variables['--color-surface'] = palette.neutral[99];
      variables['--color-surface-bright'] = palette.neutral[99];
      variables['--color-surface-dim'] = palette.neutral[87];
      variables['--color-on-surface'] = palette.neutral[10];
      variables['--color-surface-lowest'] = palette.neutral[100];
      variables['--color-surface-low'] = palette.neutral[96];
      variables['--color-surface-container'] = palette.neutral[94];
      variables['--color-surface-high'] = palette.neutral[92];
      variables['--color-surface-highest'] = palette.neutral[90];
      variables['--color-surface-variant'] = palette.neutralVariant[90];
      variables['--color-on-surface-variant'] = palette.neutralVariant[30];
      variables['--color-inverse-surface'] = palette.neutral[20];
      variables['--color-inverse-on-surface'] = palette.neutral[95];
    } else {
      variables['--color-surface'] = palette.neutral[10];
      variables['--color-surface-bright'] = palette.neutral[20];
      variables['--color-surface-dim'] = palette.neutral[6];
      variables['--color-on-surface'] = palette.neutral[90];
      variables['--color-surface-lowest'] = palette.neutral[0];
      variables['--color-surface-low'] = palette.neutral[4];
      variables['--color-surface-container'] = palette.neutral[12];
      variables['--color-surface-high'] = palette.neutral[17];
      variables['--color-surface-highest'] = palette.neutral[22];
      variables['--color-surface-variant'] = palette.neutralVariant[30];
      variables['--color-on-surface-variant'] = palette.neutralVariant[80];
      variables['--color-inverse-surface'] = palette.neutral[90];
      variables['--color-inverse-on-surface'] = palette.neutral[20];
    }

    // ==========================================================================
    // BACKGROUND COLORS
    // ==========================================================================
    variables['--color-background'] = variables['--color-surface'];
    variables['--color-on-background'] = variables['--color-on-surface'];

    // ==========================================================================
    // OUTLINE COLORS
    // ==========================================================================
    variables['--color-outline'] = mode === 'light' ? palette.neutralVariant[50] : palette.neutralVariant[60];
    variables['--color-outline-variant'] = mode === 'light' ? palette.neutralVariant[80] : palette.neutralVariant[30];

    // ==========================================================================
    // UTILITY COLORS
    // ==========================================================================
    variables['--color-shadow'] = '#000000';
    variables['--color-surface-tint'] = variables['--color-primary'];
    variables['--color-scrim'] = '#000000';

    return variables;
  }

  // ==========================================================================
  // APPLY METHODS
  // ==========================================================================

  /**
   * Apply CSS variables to document root
   * @param variables CSS variables to apply
   */
  static applyVariables(variables: CSSVariables): void {
    const root = document.documentElement;
    
    Object.entries(variables).forEach(([property, value]) => {
      root.style.setProperty(property, value);
    });
  }

  /**
   * Apply palette to document root
   * @param palette Material palette
   * @param mode Light or dark mode
   */
  static applyPalette(palette: MaterialPalette, mode: 'light' | 'dark' = 'light'): void {
    const variables = this.generateCSSVariables(palette, mode);
    this.applyVariables(variables);
  }

  /**
   * Remove all theme-related CSS variables
   */
  static clearVariables(): void {
    const root = document.documentElement;
    const variableNames = this.getAllVariableNames();
    
    variableNames.forEach(name => {
      root.style.removeProperty(name);
    });
  }

  // ==========================================================================
  // UTILITY METHODS
  // ==========================================================================

  /**
   * Get all CSS variable names managed by HCL Studio
   * @returns Array of CSS variable names
   */
  private static getAllVariableNames(): string[] {
    return [
      // Primary
      '--color-primary-key',
      '--color-primary',
      '--color-on-primary',
      '--color-primary-container',
      '--color-on-primary-container',
      '--color-inverse-primary',
      
      // Secondary
      '--color-secondary-key',
      '--color-secondary',
      '--color-on-secondary',
      '--color-secondary-container',
      '--color-on-secondary-container',
      
      // Tertiary
      '--color-tertiary-key',
      '--color-tertiary',
      '--color-on-tertiary',
      '--color-tertiary-container',
      '--color-on-tertiary-container',
      
      // Error
      '--color-error-key',
      '--color-error',
      '--color-on-error',
      '--color-error-container',
      '--color-on-error-container',
      
      // Neutral
      '--color-neutral-key',
      '--color-neutral',
      '--color-neutral-variant-key',
      '--color-neutral-variant',
      
      // Surface
      '--color-surface',
      '--color-surface-bright',
      '--color-surface-dim',
      '--color-on-surface',
      '--color-surface-lowest',
      '--color-surface-low',
      '--color-surface-container',
      '--color-surface-high',
      '--color-surface-highest',
      '--color-surface-variant',
      '--color-on-surface-variant',
      '--color-inverse-surface',
      '--color-inverse-on-surface',
      
      // Background
      '--color-background',
      '--color-on-background',
      
      // Outline
      '--color-outline',
      '--color-outline-variant',
      
      // Utility
      '--color-shadow',
      '--color-surface-tint',
      '--color-scrim'
    ];
  }

  /**
   * Get current CSS variable value
   * @param variableName CSS variable name (with or without --)
   * @returns Current variable value
   */
  static getCurrentVariableValue(variableName: string): string {
    const name = variableName.startsWith('--') ? variableName : `--${variableName}`;
    return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
  }

  /**
   * Check if dark mode is currently active
   * @returns True if dark mode is active
   */
  static isDarkModeActive(): boolean {
    // Check if surface color is dark (low lightness)
    const surfaceColor = this.getCurrentVariableValue('--color-surface');
    if (!surfaceColor) return false;
    
    try {
      // Simple check: if surface is closer to black than white, it's dark mode
      const surfaceHex = surfaceColor.startsWith('#') ? surfaceColor : '#FFFFFF';
      const surfaceRgb = this.hexToRgb(surfaceHex);
      const brightness = (surfaceRgb.r * 299 + surfaceRgb.g * 587 + surfaceRgb.b * 114) / 1000;
      return brightness < 128;
    } catch {
      return false;
    }
  }

  /**
   * Simple hex to RGB conversion for utility
   * @param hex Hex color
   * @returns RGB values
   */
  private static hexToRgb(hex: string): { r: number, g: number, b: number } {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
      r: parseInt(result[1], 16),
      g: parseInt(result[2], 16),
      b: parseInt(result[3], 16)
    } : { r: 0, g: 0, b: 0 };
  }

  // ==========================================================================
  // ANIMATION SUPPORT
  // ==========================================================================

  /**
   * Apply variables with smooth transition
   * @param variables CSS variables to apply
   * @param duration Transition duration in milliseconds
   */
  static applyVariablesWithTransition(variables: CSSVariables, duration: number = 300): void {
    const root = document.documentElement;
    
    // Add transition for smooth theme changes
    const transitionProperties = Object.keys(variables).join(', ');
    root.style.setProperty('transition', `${transitionProperties} ${duration}ms ease-in-out`);
    
    // Apply variables
    this.applyVariables(variables);
    
    // Remove transition after animation completes
    setTimeout(() => {
      root.style.removeProperty('transition');
    }, duration);
  }

  /**
   * Apply palette with smooth transition
   * @param palette Material palette
   * @param mode Light or dark mode
   * @param duration Transition duration in milliseconds
   */
  static applyPaletteWithTransition(palette: MaterialPalette, mode: 'light' | 'dark' = 'light', duration: number = 300): void {
    const variables = this.generateCSSVariables(palette, mode);
    this.applyVariablesWithTransition(variables, duration);
  }
}