/**
 * ==========================================================================
 * HCL STUDIO SERVICE
 * ==========================================================================
 * Main service for HCL-based color palette generation and theme management
 * Provides complete theme switching, persistence, and reactive updates
 * ==========================================================================
 */

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

import { 
  ThemeConfig, 
  Theme, 
  BrandColors, 
  MaterialPalette, 
  ThemePreview, 
  ThemeCollection, 
  ThemeState,
  HCLStudioOptions,
  ColorValidation 
} from './models/hcl.models';

import { PaletteGenerator } from './core/palette-generator';
import { HCLConverter } from './core/hcl-converter';
import { CSSVariableManager } from './themes/css-variable-manager';
import { ThemeStorage } from './themes/theme-storage';

@Injectable({
  providedIn: 'root'
})
export class HCLStudioService {

  // ==========================================================================
  // REACTIVE STATE
  // ==========================================================================

  private _themeState$ = new BehaviorSubject<ThemeState>({
    currentTheme: null,
    availableThemes: [],
    mode: 'light',
    isInitialized: false
  });

  private _currentMode$ = new BehaviorSubject<'light' | 'dark'>('light');

  // Public observables
  public readonly themeState$: Observable<ThemeState> = this._themeState$.asObservable();
  public readonly currentMode$: Observable<'light' | 'dark'> = this._currentMode$.asObservable();

  // ==========================================================================
  // PRIVATE STATE
  // ==========================================================================

  private builtInThemes = new Map<string, Theme>();
  private customThemes = new Map<string, Theme>();
  private currentTheme: Theme | null = null;
  private currentMode: 'light' | 'dark' = 'light';
  private options: HCLStudioOptions = {};

  // ==========================================================================
  // INITIALIZATION
  // ==========================================================================

  /**
   * Initialize HCL Studio with options and themes
   * @param options Initialization options
   */
  initialize(options: HCLStudioOptions = {}): void {
    this.options = {
      autoMode: false,
      storageKey: 'hcl-studio',
      validation: {
        enableContrastCheck: true,
        enableColorBlindCheck: false,
        minContrastRatio: 4.5
      },
      ...options
    };

    // Load built-in themes if provided
    if (options.themes) {
      this.registerThemes(options.themes);
    }

    // Load custom themes from storage
    this.loadCustomThemesFromStorage();

    // Restore user's last theme and mode
    this.restoreUserPreferences();

    // Apply default theme if specified
    if (options.defaultTheme) {
      if (typeof options.defaultTheme === 'string') {
        this.switchTheme(options.defaultTheme);
      } else {
        this.applyThemeConfig(options.defaultTheme);
      }
    }

    // Set up system theme detection if enabled
    if (options.autoMode) {
      this.setupAutoModeDetection();
    }

    this.updateThemeState();
    this.markAsInitialized();
  }

  /**
   * Quick initialize with brand colors
   * @param brandColors Primary, secondary, tertiary colors
   * @param mode Initial mode
   */
  initializeWithColors(brandColors: BrandColors, mode: 'light' | 'dark' = 'light'): void {
    const themeConfig: ThemeConfig = {
      id: 'brand-theme',
      name: 'Brand Theme',
      colors: brandColors,
      mode,
      createdAt: new Date()
    };

    this.initialize({
      defaultTheme: themeConfig,
      autoMode: false
    });
  }

  // ==========================================================================
  // THEME MANAGEMENT
  // ==========================================================================

  /**
   * Register multiple themes
   * @param themes Theme collection
   */
  registerThemes(themes: ThemeCollection): void {
    Object.entries(themes).forEach(([id, config]) => {
      const themeConfig: ThemeConfig = { id, ...config };
      const theme = this.createCompleteTheme(themeConfig);
      this.builtInThemes.set(id, theme);
    });
    
    this.updateThemeState();
  }

  /**
   * Create and save custom theme
   * @param id Theme identifier
   * @param name Theme display name
   * @param brandColors Brand colors
   * @param description Optional description
   * @returns Created theme
   */
  createCustomTheme(id: string, name: string, brandColors: BrandColors, description?: string): Theme {
    const themeConfig: ThemeConfig = {
      id,
      name,
      colors: brandColors,
      description,
      createdAt: new Date()
    };

    const theme = this.createCompleteTheme(themeConfig);
    this.customThemes.set(id, theme);
    
    // Save to storage
    ThemeStorage.saveCustomTheme(themeConfig);
    
    this.updateThemeState();
    return theme;
  }

  /**
   * Switch to different theme
   * @param themeId Theme identifier
   * @param mode Optional mode override
   */
  switchTheme(themeId: string, mode?: 'light' | 'dark'): void {
    const theme = this.getTheme(themeId);
    if (!theme) {
      console.warn(`Theme not found: ${themeId}`);
      return;
    }

    this.currentTheme = theme;
    
    if (mode) {
      this.currentMode = mode;
      this._currentMode$.next(mode);
      ThemeStorage.saveCurrentMode(mode);
    }

    // Apply the palette
    const palette = this.currentMode === 'light' ? theme.lightPalette : theme.darkPalette;
    CSSVariableManager.applyPaletteWithTransition(palette, this.currentMode);

    // Save preference
    ThemeStorage.saveCurrentTheme(themeId);
    
    this.updateThemeState();
  }

  /**
   * Apply theme configuration directly
   * @param themeConfig Theme configuration
   */
  applyThemeConfig(themeConfig: ThemeConfig): void {
    const theme = this.createCompleteTheme(themeConfig);
    this.currentTheme = theme;
    
    const resolvedMode = themeConfig.mode === 'auto' ? this.currentMode : (themeConfig.mode || this.currentMode);
    const palette = resolvedMode === 'light' ? theme.lightPalette : theme.darkPalette;
    
    CSSVariableManager.applyPaletteWithTransition(palette, resolvedMode);
    
    this.currentMode = resolvedMode;
    this._currentMode$.next(resolvedMode);
    
    this.updateThemeState();
  }

  /**
   * Toggle between light and dark mode
   */
  toggleMode(): void {
    const newMode = this.currentMode === 'light' ? 'dark' : 'light';
    this.switchMode(newMode);
  }

  /**
   * Switch to specific mode
   * @param mode Target mode
   */
  switchMode(mode: 'light' | 'dark'): void {
    if (this.currentMode === mode) return;
    
    this.currentMode = mode;
    this._currentMode$.next(mode);
    
    if (this.currentTheme) {
      const palette = mode === 'light' ? this.currentTheme.lightPalette : this.currentTheme.darkPalette;
      CSSVariableManager.applyPaletteWithTransition(palette, mode);
    }
    
    ThemeStorage.saveCurrentMode(mode);
    this.updateThemeState();
  }

  // ==========================================================================
  // COLOR UTILITIES
  // ==========================================================================

  /**
   * Generate color preview for theme selection
   * @param brandColors Brand colors
   * @returns Preview color object
   */
  generateColorPreview(brandColors: BrandColors): { [key: string]: string } {
    return PaletteGenerator.generateColorPreview(brandColors);
  }

  /**
   * Validate color format and accessibility
   * @param color Color string to validate
   * @returns Validation results
   */
  validateColor(color: string): ColorValidation {
    const warnings: string[] = [];
    const recommendations: string[] = [];

    // Check format validity
    if (!HCLConverter.isValidHex(color)) {
      warnings.push('Invalid hex color format');
      return { isValid: false, warnings, recommendations };
    }

    // Check if color is too light/dark for accessibility
    const hcl = HCLConverter.hexToHcl(color);
    
    if (hcl.l < 10) {
      warnings.push('Color may be too dark for some use cases');
      recommendations.push('Consider using lighter tones for better contrast');
    }
    
    if (hcl.l > 90) {
      warnings.push('Color may be too light for some use cases');
      recommendations.push('Consider using darker tones for better contrast');
    }

    // Check chroma levels
    if (hcl.c < 10) {
      recommendations.push('Low chroma - color may appear washed out');
    }

    if (hcl.c > 80) {
      recommendations.push('High chroma - consider reducing saturation for better balance');
    }

    return {
      isValid: warnings.length === 0,
      warnings,
      recommendations: recommendations.length > 0 ? recommendations : undefined
    };
  }

  // ==========================================================================
  // GETTERS
  // ==========================================================================

  /**
   * Get current theme state
   * @returns Current theme state
   */
  getCurrentThemeState(): ThemeState {
    return this._themeState$.value;
  }

  /**
   * Get current theme
   * @returns Current theme or null
   */
  getCurrentTheme(): Theme | null {
    return this.currentTheme;
  }

  /**
   * Get current mode
   * @returns Current mode
   */
  getCurrentMode(): 'light' | 'dark' {
    return this.currentMode;
  }

  /**
   * Get all available themes
   * @returns Array of theme previews
   */
  getAvailableThemes(): ThemePreview[] {
    const themes: ThemePreview[] = [];

    // Add built-in themes
    this.builtInThemes.forEach(theme => {
      themes.push({
        id: theme.config.id,
        name: theme.config.name,
        description: theme.config.description,
        primary: theme.config.colors.primary,
        secondary: theme.config.colors.secondary,
        tertiary: theme.config.colors.tertiary
      });
    });

    // Add custom themes
    this.customThemes.forEach(theme => {
      themes.push({
        id: theme.config.id,
        name: theme.config.name,
        description: theme.config.description,
        primary: theme.config.colors.primary,
        secondary: theme.config.colors.secondary,
        tertiary: theme.config.colors.tertiary
      });
    });

    return themes;
  }

  /**
   * Check if service is initialized
   * @returns True if initialized
   */
  isInitialized(): boolean {
    return this._themeState$.value.isInitialized;
  }

  // ==========================================================================
  // IMPORT/EXPORT
  // ==========================================================================

  /**
   * Export theme configuration
   * @param themeId Theme to export
   * @returns JSON string or null
   */
  exportTheme(themeId: string): string | null {
    return ThemeStorage.exportTheme(themeId);
  }

  /**
   * Import theme from JSON
   * @param jsonString Theme JSON data
   * @returns Imported theme or null
   */
  importTheme(jsonString: string): ThemeConfig | null {
    const imported = ThemeStorage.importTheme(jsonString);
    if (imported) {
      // Reload custom themes to include the new one
      this.loadCustomThemesFromStorage();
      this.updateThemeState();
    }
    return imported;
  }

  // ==========================================================================
  // PRIVATE METHODS
  // ==========================================================================

  /**
   * Create complete theme with both light and dark palettes
   * @param config Theme configuration
   * @returns Complete theme
   */
  private createCompleteTheme(config: ThemeConfig): Theme {
    const lightPalette = PaletteGenerator.generateMaterialPalette(config.colors, 'light');
    const darkPalette = PaletteGenerator.generateMaterialPalette(config.colors, 'dark');

    const lightCSSVariables = CSSVariableManager.generateCSSVariables(lightPalette, 'light');
    const darkCSSVariables = CSSVariableManager.generateCSSVariables(darkPalette, 'dark');

    return {
      config,
      lightPalette,
      darkPalette,
      cssVariables: lightCSSVariables // Default to light mode variables
    };
  }

  /**
   * Get theme by ID (checks both built-in and custom)
   * @param themeId Theme identifier
   * @returns Theme or null
   */
  private getTheme(themeId: string): Theme | null {
    return this.builtInThemes.get(themeId) || this.customThemes.get(themeId) || null;
  }

  /**
   * Load custom themes from storage
   */
  private loadCustomThemesFromStorage(): void {
    const customThemes = ThemeStorage.getCustomThemes();
    
    Object.values(customThemes).forEach(config => {
      const theme = this.createCompleteTheme(config);
      this.customThemes.set(config.id, theme);
    });
  }

  /**
   * Restore user's theme preferences
   */
  private restoreUserPreferences(): void {
    const savedThemeId = ThemeStorage.getCurrentTheme();
    const savedMode = ThemeStorage.getCurrentMode();
    
    this.currentMode = savedMode;
    this._currentMode$.next(savedMode);
    
    if (savedThemeId && this.getTheme(savedThemeId)) {
      this.switchTheme(savedThemeId, savedMode);
    }
  }

  /**
   * Set up automatic mode detection based on system preference
   */
  private setupAutoModeDetection(): void {
    if (typeof window !== 'undefined' && window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      
      const handleChange = (e: MediaQueryListEvent) => {
        const systemMode = e.matches ? 'dark' : 'light';
        this.switchMode(systemMode);
      };
      
      // Set initial mode
      const initialSystemMode = mediaQuery.matches ? 'dark' : 'light';
      this.switchMode(initialSystemMode);
      
      // Listen for changes
      mediaQuery.addEventListener('change', handleChange);
    }
  }

  /**
   * Update reactive theme state
   */
  private updateThemeState(): void {
    const state: ThemeState = {
      currentTheme: this.currentTheme,
      availableThemes: this.getAvailableThemes(),
      mode: this.currentMode,
      isInitialized: this._themeState$.value.isInitialized
    };
    
    this._themeState$.next(state);
  }

  /**
   * Mark service as initialized
   */
  private markAsInitialized(): void {
    const currentState = this._themeState$.value;
    this._themeState$.next({
      ...currentState,
      isInitialized: true
    });
  }
}