/**
 * DSS Theme Loader Service
 *
 * Manages the loading and hot-reloading of DSS CSS layers.
 * Handles the "Bootstrapping Paradox" by providing fallback mechanisms
 * when token files are missing or corrupted.
 *
 * CSS Layer Order:
 * 1. dss-core.css (structural) - REQUIRED, always loaded first
 * 2. dss-tokens.css (design tokens) - Can be regenerated from Figma
 * 3. dss-theme.css (semantic mapping) - Maps tokens to purposes
 * 4. dss-components.css (styled components) - Uses semantic tokens
 */

import logger from './logger.js';
import { notifySuccess, notifyError, notifyInfo, ErrorCode } from './messaging.js';

// CSS Layer definitions with fallback behavior
const CSS_LAYERS = [
  {
    id: 'dss-core',
    path: '/admin-ui/css/dss-core.css',
    name: 'Core/Structural',
    required: true,
    fallback: null // No fallback - this is the baseline
  },
  {
    id: 'dss-tokens',
    path: '/admin-ui/css/dss-tokens.css',
    name: 'Design Tokens',
    required: false,
    fallback: '/admin-ui/css/dss-tokens-fallback.css'
  },
  {
    id: 'dss-theme',
    path: '/admin-ui/css/dss-theme.css',
    name: 'Semantic Theme',
    required: false,
    fallback: null
  },
  {
    id: 'dss-components',
    path: '/admin-ui/css/dss-components.css',
    name: 'Component Styles',
    required: false,
    fallback: null
  }
];

class ThemeLoaderService {
  constructor() {
    this.layers = new Map();
    this.isInitialized = false;
    this.healthCheckInterval = null;
    this.listeners = new Set();
  }

  /**
   * Initialize the theme loader
   * Validates all CSS layers are loaded and functional
   */
  async init() {
    logger.info('ThemeLoader', 'Initializing DSS Theme Loader...');

    try {
      // Perform health check on all layers
      const healthStatus = await this.healthCheck();

      if (healthStatus.allHealthy) {
        logger.info('ThemeLoader', 'All CSS layers loaded successfully');
        this.isInitialized = true;
        notifySuccess('Design system styles loaded successfully');
      } else {
        logger.warn('ThemeLoader', 'Some CSS layers failed to load', {
          failed: healthStatus.failed
        });
        notifyInfo(`Design system loaded with ${healthStatus.failed.length} layer(s) using fallbacks`);
      }

      // Start periodic health checks (every 30 seconds)
      this.startHealthCheckInterval();

      return healthStatus;
    } catch (error) {
      logger.error('ThemeLoader', 'Failed to initialize theme loader', { error: error.message });
      notifyError('Failed to load design system styles', ErrorCode.SYSTEM_STARTUP_FAILED);
      throw error;
    }
  }

  /**
   * Check health of all CSS layers
   * Returns status of each layer and overall health
   */
  async healthCheck() {
    const results = {
      allHealthy: true,
      layers: [],
      failed: [],
      timestamp: new Date().toISOString()
    };

    for (const layer of CSS_LAYERS) {
      const linkElement = document.querySelector(`link[href*="${layer.id}"]`);
      const status = {
        id: layer.id,
        name: layer.name,
        loaded: false,
        path: layer.path,
        error: null
      };

      if (linkElement) {
        // Check if stylesheet is loaded and accessible
        try {
          const response = await fetch(layer.path, { method: 'HEAD' });
          status.loaded = response.ok;
          if (!response.ok) {
            status.error = `HTTP ${response.status}`;
          }
        } catch (error) {
          status.error = error.message;
        }
      } else {
        status.error = 'Link element not found in DOM';
      }

      if (!status.loaded && layer.required) {
        results.allHealthy = false;
        results.failed.push(layer.id);
      } else if (!status.loaded && !layer.required && layer.fallback) {
        // Try to load fallback
        await this.loadFallback(layer);
      }

      results.layers.push(status);
      this.layers.set(layer.id, status);
    }

    // Notify listeners of health check results
    this.notifyListeners('healthCheck', results);

    return results;
  }

  /**
   * Load a fallback CSS file for a failed layer
   */
  async loadFallback(layer) {
    if (!layer.fallback) return false;

    try {
      const response = await fetch(layer.fallback, { method: 'HEAD' });
      if (response.ok) {
        const linkElement = document.querySelector(`link[href*="${layer.id}"]`);
        if (linkElement) {
          linkElement.href = layer.fallback;
          logger.info('ThemeLoader', `Loaded fallback for ${layer.name}`, { fallback: layer.fallback });
          return true;
        }
      }
    } catch (error) {
      logger.warn('ThemeLoader', `Failed to load fallback for ${layer.name}`, { error: error.message });
    }

    return false;
  }

  /**
   * Reload a specific CSS layer
   * Used when tokens are regenerated from Figma
   */
  async reloadLayer(layerId) {
    const layer = CSS_LAYERS.find(l => l.id === layerId);
    if (!layer) {
      logger.warn('ThemeLoader', `Unknown layer: ${layerId}`);
      return false;
    }

    logger.info('ThemeLoader', `Reloading layer: ${layer.name}`);

    try {
      const linkElement = document.querySelector(`link[href*="${layer.id}"]`);
      if (!linkElement) {
        logger.error('ThemeLoader', `Link element not found for ${layer.id}`);
        return false;
      }

      // Force reload by adding cache-busting timestamp
      const timestamp = Date.now();
      const newHref = `${layer.path}?t=${timestamp}`;

      // Create a promise that resolves when the new stylesheet loads
      return new Promise((resolve, reject) => {
        const tempLink = document.createElement('link');
        tempLink.rel = 'stylesheet';
        tempLink.href = newHref;

        tempLink.onload = () => {
          // Replace old link with new one
          linkElement.href = newHref;
          tempLink.remove();
          logger.info('ThemeLoader', `Successfully reloaded ${layer.name}`);
          this.notifyListeners('layerReloaded', { layerId, timestamp });
          resolve(true);
        };

        tempLink.onerror = () => {
          tempLink.remove();
          logger.error('ThemeLoader', `Failed to reload ${layer.name}`);
          reject(new Error(`Failed to reload ${layer.name}`));
        };

        // Add temp link to head to trigger load
        document.head.appendChild(tempLink);

        // Timeout after 5 seconds
        setTimeout(() => {
          if (document.head.contains(tempLink)) {
            tempLink.remove();
            reject(new Error(`Timeout loading ${layer.name}`));
          }
        }, 5000);
      });
    } catch (error) {
      logger.error('ThemeLoader', `Error reloading ${layer.name}`, { error: error.message });
      return false;
    }
  }

  /**
   * Reload all CSS layers (hot reload)
   */
  async reloadAllLayers() {
    logger.info('ThemeLoader', 'Reloading all CSS layers...');
    notifyInfo('Reloading design system styles...');

    const results = [];
    for (const layer of CSS_LAYERS) {
      const success = await this.reloadLayer(layer.id);
      results.push({ id: layer.id, success });
    }

    const failed = results.filter(r => !r.success);
    if (failed.length === 0) {
      notifySuccess('All styles reloaded successfully');
    } else {
      notifyError(`Failed to reload ${failed.length} layer(s)`);
    }

    return results;
  }

  /**
   * Reload only the tokens layer
   * Used after Figma sync or token generation
   */
  async reloadTokens() {
    logger.info('ThemeLoader', 'Reloading design tokens...');
    notifyInfo('Applying new design tokens...');

    try {
      await this.reloadLayer('dss-tokens');
      // Also reload theme since it depends on tokens
      await this.reloadLayer('dss-theme');
      notifySuccess('Design tokens applied successfully');
      return true;
    } catch (error) {
      notifyError('Failed to apply design tokens');
      return false;
    }
  }

  /**
   * Start periodic health check interval
   */
  startHealthCheckInterval(intervalMs = 30000) {
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval);
    }

    this.healthCheckInterval = setInterval(async () => {
      const status = await this.healthCheck();
      if (!status.allHealthy) {
        logger.warn('ThemeLoader', 'Health check detected issues', {
          failed: status.failed
        });
      }
    }, intervalMs);
  }

  /**
   * Stop periodic health checks
   */
  stopHealthCheckInterval() {
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval);
      this.healthCheckInterval = null;
    }
  }

  /**
   * Get current theme status
   */
  getStatus() {
    return {
      initialized: this.isInitialized,
      layers: Array.from(this.layers.values()),
      layerCount: CSS_LAYERS.length
    };
  }

  /**
   * Subscribe to theme loader events
   */
  subscribe(callback) {
    this.listeners.add(callback);
    return () => this.listeners.delete(callback);
  }

  /**
   * Notify all listeners of an event
   */
  notifyListeners(event, data) {
    this.listeners.forEach(callback => {
      try {
        callback(event, data);
      } catch (error) {
        logger.error('ThemeLoader', 'Listener error', { error: error.message });
      }
    });
  }

  /**
   * Generate CSS token file from extracted tokens
   * This is called after Figma sync to create dss-tokens.css
   */
  async generateTokensFile(tokens) {
    logger.info('ThemeLoader', 'Generating tokens CSS file...');

    // Convert tokens object to CSS custom properties
    const cssContent = this.tokensToCSS(tokens);

    // Send to backend to save file
    try {
      const response = await fetch('/api/dss/save-tokens', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          content: cssContent,
          path: '/admin-ui/css/dss-tokens.css'
        })
      });

      if (response.ok) {
        logger.info('ThemeLoader', 'Tokens file generated successfully');
        await this.reloadTokens();
        return true;
      } else {
        throw new Error(`Server returned ${response.status}`);
      }
    } catch (error) {
      logger.error('ThemeLoader', 'Failed to generate tokens file', { error: error.message });
      notifyError('Failed to save design tokens');
      return false;
    }
  }

  /**
   * Convert tokens object to CSS custom properties
   */
  tokensToCSS(tokens) {
    let css = `/**
 * DSS Design Tokens - Generated ${new Date().toISOString()}
 * Source: Figma extraction
 */

:root {
`;

    // Recursively flatten tokens and create CSS variables
    const flattenTokens = (obj, prefix = '--ds') => {
      let result = '';
      for (const [key, value] of Object.entries(obj)) {
        const varName = `${prefix}-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
        if (typeof value === 'object' && value !== null && !value.$value) {
          result += flattenTokens(value, varName);
        } else {
          const cssValue = value.$value || value;
          result += `  ${varName}: ${cssValue};\n`;
        }
      }
      return result;
    };

    css += flattenTokens(tokens);
    css += '}\n';

    return css;
  }

  /**
   * Export current tokens as JSON
   */
  async exportTokens() {
    const computedStyle = getComputedStyle(document.documentElement);
    const tokens = {};

    // Extract all --ds-* variables
    const styleSheets = document.styleSheets;
    for (const sheet of styleSheets) {
      try {
        for (const rule of sheet.cssRules) {
          if (rule.selectorText === ':root') {
            const text = rule.cssText;
            const matches = text.matchAll(/--ds-([^:]+):\s*([^;]+);/g);
            for (const match of matches) {
              const [, name, value] = match;
              tokens[name] = value.trim();
            }
          }
        }
      } catch (e) {
        // CORS restrictions on external stylesheets
      }
    }

    return tokens;
  }
}

// Export singleton instance
const themeLoader = new ThemeLoaderService();
export default themeLoader;
export { ThemeLoaderService, CSS_LAYERS };
