import { FontDefinition, FontPreset } from '../types/font-types';

export class FontPresetManager {
  private customPresets = new Map<string, FontPreset>();
  private fontCategories = new Map<string, string[]>();

  constructor() {
    this.initializeCategories();
  }

  /**
   * Add a custom font preset collection
   */
  addPresetCollection(name: string, preset: FontPreset): void {
    this.customPresets.set(name, preset);
    
    // Update categories
    Object.entries(preset).forEach(([fontName, definition]) => {
      this.addToCategory(definition.category, fontName);
    });
  }

  /**
   * Add a single custom font
   */
  addCustomFont(name: string, definition: FontDefinition): void {
    const customPreset = this.customPresets.get('custom') || {};
    customPreset[name] = definition;
    this.customPresets.set('custom', customPreset);
    
    this.addToCategory(definition.category, name);
  }

  /**
   * Add font from external service (Typekit, custom CDN, etc.)
   */
  addExternalFont(name: string, config: {
    family: string;
    url: string;
    weights?: number[];
    category?: FontDefinition['category'];
    fallbacks?: string[];
  }): void {
    const definition: FontDefinition = {
      family: config.family,
      url: config.url,
      weights: config.weights || [400],
      fallbacks: config.fallbacks || this.getDefaultFallbacks(config.category || 'sans-serif'),
      loadingStrategy: 'swap',
      category: config.category || 'sans-serif'
    };

    this.addCustomFont(name, definition);
  }

  /**
   * Add Adobe Typekit font
   */
  addTypekitFont(kitId: string, fonts: Array<{
    name: string;
    family: string;
    weights?: number[];
    category?: FontDefinition['category'];
  }>): void {
    const typekitUrl = `https://use.typekit.net/${kitId}.css`;
    
    fonts.forEach(font => {
      this.addExternalFont(font.name, {
        family: font.family,
        url: typekitUrl,
        weights: font.weights,
        category: font.category
      });
    });
  }

  /**
   * Add self-hosted font
   */
  addSelfHostedFont(name: string, config: {
    family: string;
    basePath: string; // e.g., '/assets/fonts/my-font'
    formats: Array<'woff2' | 'woff' | 'ttf' | 'otf'>;
    weights?: number[];
    category?: FontDefinition['category'];
    fallbacks?: string[];
  }): void {
    // Generate CSS for self-hosted font
    const fontFaceCSS = this.generateFontFaceCSS(config);
    
    const definition: FontDefinition = {
      family: config.family,
      url: `data:text/css;base64,${btoa(fontFaceCSS)}`, // Inline CSS
      weights: config.weights || [400],
      fallbacks: config.fallbacks || this.getDefaultFallbacks(config.category || 'sans-serif'),
      loadingStrategy: 'swap',
      category: config.category || 'sans-serif'
    };

    this.addCustomFont(name, definition);
  }

  /**
   * Get all custom presets
   */
  getCustomPresets(): Map<string, FontPreset> {
    return this.customPresets;
  }

  /**
   * Get fonts by category
   */
  getFontsByCategory(category: string): string[] {
    return this.fontCategories.get(category) || [];
  }

  /**
   * Get all categories
   */
  getCategories(): string[] {
    return Array.from(this.fontCategories.keys());
  }

  /**
   * Remove custom font
   */
  removeCustomFont(name: string): boolean {
    const customPreset = this.customPresets.get('custom');
    if (customPreset && customPreset[name]) {
      const category = customPreset[name].category;
      delete customPreset[name];
      
      // Remove from category
      this.removeFromCategory(category, name);
      return true;
    }
    return false;
  }

  /**
   * Import fonts from a configuration object
   */
  importConfiguration(config: {
    name: string;
    fonts: { [key: string]: Omit<FontDefinition, 'loadingStrategy'> };
  }): void {
    const preset: FontPreset = {};
    
    Object.entries(config.fonts).forEach(([name, fontConfig]) => {
      preset[name] = {
        ...fontConfig,
        loadingStrategy: 'swap'
      };
    });

    this.addPresetCollection(config.name, preset);
  }

  /**
   * Export custom fonts configuration
   */
  exportConfiguration(): string {
    const config = {
      customPresets: Object.fromEntries(this.customPresets),
      categories: Object.fromEntries(this.fontCategories)
    };
    
    return JSON.stringify(config, null, 2);
  }

  private initializeCategories(): void {
    this.fontCategories.set('sans-serif', []);
    this.fontCategories.set('serif', []);
    this.fontCategories.set('monospace', []);
    this.fontCategories.set('display', []);
    this.fontCategories.set('handwriting', []);
  }

  private addToCategory(category: string, fontName: string): void {
    const fonts = this.fontCategories.get(category) || [];
    if (!fonts.includes(fontName)) {
      fonts.push(fontName);
      this.fontCategories.set(category, fonts);
    }
  }

  private removeFromCategory(category: string, fontName: string): void {
    const fonts = this.fontCategories.get(category) || [];
    const index = fonts.indexOf(fontName);
    if (index > -1) {
      fonts.splice(index, 1);
      this.fontCategories.set(category, fonts);
    }
  }

  private getDefaultFallbacks(category: FontDefinition['category']): string[] {
    switch (category) {
      case 'serif':
        return ['Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'];
      case 'monospace':
        return ['Consolas', 'Monaco', 'Courier New', 'monospace'];
      case 'handwriting':
        return ['cursive'];
      case 'display':
      case 'sans-serif':
      default:
        return ['ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'];
    }
  }

  private generateFontFaceCSS(config: {
    family: string;
    basePath: string;
    formats: Array<'woff2' | 'woff' | 'ttf' | 'otf'>;
    weights?: number[];
  }): string {
    const weights = config.weights || [400];
    let css = '';

    weights.forEach(weight => {
      css += `@font-face {
  font-family: '${config.family}';
  src: ${config.formats.map(format => {
    const ext = format;
    const type = format === 'ttf' ? 'truetype' : format === 'otf' ? 'opentype' : format;
    return `url('${config.basePath}-${weight}.${ext}') format('${type}')`;
  }).join(',\n       ')};
  font-weight: ${weight};
  font-display: swap;
}

`;
    });

    return css;
  }
}

// Singleton instance
export const fontPresetManager = new FontPresetManager();