// @lifecycle canonical - Orchestrates style selection and provides style guidance.
/**
 * Style Manager
 *
 * Orchestration layer for the style system, following the GateManager pattern.
 * Provides:
 * - Style lookup and guidance retrieval
 * - Compatibility checking with frameworks
 * - Hot-reload support via cache invalidation
 *
 * @see GateManager for the pattern this follows
 */

import {
  StyleDefinitionLoader,
  createStyleDefinitionLoader,
  type StyleDefinitionLoaderConfig,
  type StyleLoaderStats,
  type StyleDefinitionYaml,
} from './core/index.js';
import { isGateActiveForContext } from '../../engine/gates/utils/gate-activation.js';

import type { StyleManagerPort, Logger } from '../../shared/types/index.js';

/**
 * Configuration for StyleManager
 */
export interface StyleManagerConfig {
  /** Configuration for the underlying StyleDefinitionLoader */
  loaderConfig?: Partial<StyleDefinitionLoaderConfig>;
  /** Enable debug logging */
  debug?: boolean;
}

/**
 * Style activation context for determining auto-application
 */
export interface StyleActivationContext {
  /** Prompt category being executed */
  promptCategory?: string;
  /** Current framework (e.g., 'CAGEERF', 'REACT') */
  framework?: string;
  /** Whether style was explicitly requested */
  explicitRequest?: boolean;
}

/**
 * Style Manager
 *
 * Provides orchestration for the style system, managing style selection
 * and guidance retrieval.
 *
 * @example
 * ```typescript
 * const manager = new StyleManager(logger);
 * await manager.initialize();
 *
 * // Get style guidance
 * const guidance = manager.getStyleGuidance('analytical');
 * console.log(guidance);
 *
 * // Check available styles
 * const styles = manager.listStyles();
 * ```
 */
export class StyleManager implements StyleManagerPort {
  private loader: StyleDefinitionLoader | null = null;
  private logger: Logger;
  private config: Required<StyleManagerConfig>;
  private initialized: boolean = false;

  constructor(logger: Logger, config: StyleManagerConfig = {}) {
    this.logger = logger;
    this.config = {
      loaderConfig: config.loaderConfig ?? {},
      debug: config.debug ?? false,
    };
  }

  /**
   * Initialize the style manager and loader
   */
  async initialize(): Promise<void> {
    if (this.initialized) {
      this.logger.debug('StyleManager already initialized');
      return;
    }

    this.logger.info('Initializing StyleManager...');
    const startTime = performance.now();

    try {
      // Initialize the style loader
      this.loader = createStyleDefinitionLoader({
        ...this.config.loaderConfig,
        debug: this.config.debug,
      });

      const loadTime = performance.now() - startTime;
      this.initialized = true;

      const styles = this.loader.discoverStyles();
      this.logger.info(
        `StyleManager initialized with ${styles.length} styles in ${loadTime.toFixed(1)}ms`
      );

      if (this.config.debug && styles.length > 0) {
        this.logger.debug(`Available styles: ${styles.join(', ')}`);
      }
    } catch (error) {
      this.logger.error('Failed to initialize StyleManager:', error);
      throw error;
    }
  }

  /**
   * Get a specific style definition by ID
   *
   * @param styleId - The style ID (case-insensitive)
   * @returns The style definition or undefined if not found
   */
  getStyle(styleId: string): StyleDefinitionYaml | undefined {
    this.ensureInitialized();
    return this.loader!.loadStyle(styleId);
  }

  /**
   * Get style guidance text by ID
   *
   * @param styleId - The style ID (case-insensitive)
   * @returns The guidance text or null if not found
   */
  getStyleGuidance(styleId: string): string | null {
    this.ensureInitialized();
    const style = this.loader!.loadStyle(styleId);
    return style?.guidance ?? null;
  }

  /**
   * Check if a style exists
   *
   * @param styleId - The style ID to check
   * @returns true if the style exists
   */
  hasStyle(styleId: string): boolean {
    this.ensureInitialized();
    return this.loader!.styleExists(styleId);
  }

  /**
   * List all registered style IDs
   *
   * @returns Array of style IDs
   */
  listStyles(): string[] {
    this.ensureInitialized();
    return this.loader!.discoverStyles();
  }

  /**
   * Get all style definitions
   *
   * @returns Map of ID to definition
   */
  getAllStyles(): Map<string, StyleDefinitionYaml> {
    this.ensureInitialized();
    return this.loader!.loadAllStyles();
  }

  /**
   * Check if a style is compatible with a framework
   *
   * @param styleId - The style ID
   * @param frameworkId - The framework ID to check compatibility with
   * @returns true if compatible (or no restrictions defined)
   */
  isStyleCompatible(styleId: string, frameworkId?: string): boolean {
    const style = this.getStyle(styleId);
    if (!style?.compatibleFrameworks) return true; // No restriction
    if (!frameworkId) return true;
    return style.compatibleFrameworks.some((f) => f.toUpperCase() === frameworkId.toUpperCase());
  }

  /**
   * Check if a style should be auto-applied for a given context
   *
   * Uses the canonical gate activation utility for rule checking.
   * Note: Styles differ from gates in that no activation rules = NOT auto-applied.
   *
   * @param styleId - The style ID
   * @param context - Activation context
   * @returns true if the style should be auto-applied
   */
  isStyleActive(styleId: string, context: StyleActivationContext): boolean {
    const style = this.getStyle(styleId);
    if (!style) return false;
    if (!style.enabled) return false;
    if (!style.activation) return false; // Styles require explicit activation rules

    // Use canonical gate activation utility for rule checking
    return isGateActiveForContext(style.activation, {
      promptCategory: context.promptCategory,
      framework: context.framework,
      explicitRequest: context.explicitRequest,
    });
  }

  /**
   * Clear cached style definitions
   *
   * @param styleId - Optional specific style ID to clear
   */
  clearCache(styleId?: string): void {
    this.ensureInitialized();
    this.loader!.clearCache(styleId);
    if (styleId) {
      this.logger.debug(`Cleared cache for style: ${styleId}`);
    } else {
      this.logger.debug('Cleared all style caches');
    }
  }

  /**
   * Get loader statistics
   */
  getLoaderStats(): StyleLoaderStats {
    this.ensureInitialized();
    return this.loader!.getStats();
  }

  /**
   * Get the underlying loader (for testing/advanced use)
   */
  getLoader(): StyleDefinitionLoader {
    this.ensureInitialized();
    return this.loader!;
  }

  /**
   * Get combined style system status
   */
  getStatus(): {
    initialized: boolean;
    availableStyles: string[];
    loaderStats: StyleLoaderStats | null;
  } {
    return {
      initialized: this.initialized,
      availableStyles: this.initialized ? this.loader!.discoverStyles() : [],
      loaderStats: this.initialized ? this.loader!.getStats() : null,
    };
  }

  // ============================================================================
  // Private Implementation
  // ============================================================================

  /**
   * Ensure the manager is initialized before operations
   */
  private ensureInitialized(): void {
    if (!this.initialized || !this.loader) {
      throw new Error('StyleManager not initialized. Call initialize() first.');
    }
  }
}

/**
 * Create and initialize a StyleManager
 */
export async function createStyleManager(
  logger: Logger,
  config?: StyleManagerConfig
): Promise<StyleManager> {
  const manager = new StyleManager(logger, config);
  await manager.initialize();
  return manager;
}
