import { invoke } from '@tauri-apps/api/core';
import { StyleOption, DocxStyleConfig, ElementStyle, FontConfig, ColorPalette } from '../types';
import { generatePreviewCss, generateWordConfig } from './templateRenderer';

interface RawTemplate {
  id: string;
  name: string;
  category?: string;
  description?: string;
  vibe?: string;
  googleFontsImport?: string;
  typography?: {
    fonts?: FontConfig;
    colors?: ColorPalette;
  };
  elements?: Record<string, ElementStyle>;
  page?: Record<string, any>;
  wordConfig?: Record<string, any>;
  previewCss?: string;
  [key: string]: any;
}

interface TemplateFile {
  name: string;
  content: string;
  category: string; // Folder-based category from Rust
}

/**
 * Resolves a color reference or returns the color directly
 */
function resolveColor(color: string | undefined, palette: ColorPalette): string {
  if (!color) return '#000000';
  if (palette[color as keyof ColorPalette]) {
    return '#' + palette[color as keyof ColorPalette];
  }
  return color.startsWith('#') ? color : '#' + color;
}

/**
 * Resolves a font reference or returns the font directly
 */
function resolveFont(font: string | undefined, fonts: FontConfig): string {
  if (!font) return 'serif';
  if (fonts[font as keyof FontConfig]) {
    return fonts[font as keyof FontConfig]!;
  }
  return font;
}

/**
 * Generates preview CSS from unified template structure
 */


/**


/**
 * Validate that a parsed object conforms to the StyleOption interface
 */
function validateTemplate(raw: RawTemplate, filename: string): StyleOption | null {
  if (!raw.id || typeof raw.id !== 'string') {
    console.error(`Invalid template in ${filename}: missing or invalid 'id'`);
    return null;
  }
  if (!raw.name || typeof raw.name !== 'string') {
    console.error(`Invalid template in ${filename}: missing or invalid 'name'`);
    return null;
  }

  const hasUnifiedStructure = raw.elements && raw.typography;

  let wordConfig: StyleOption['wordConfig'];
  let previewCss: string;

  if (hasUnifiedStructure) {
    const fonts = raw.typography?.fonts || {};
    const palette = raw.typography?.colors || {};
    const elements = raw.elements || {};

    // Only generate wordConfig if it's missing or incomplete in the raw template
    // Prefer the raw wordConfig if it exists (allows manual overrides)
    if (raw.wordConfig && Object.keys(raw.wordConfig).length > 0) {
      wordConfig = raw.wordConfig as StyleOption['wordConfig'];
    } else {
      // Use the imported generator which now has better logic
      wordConfig = generateWordConfig(elements, fonts, palette) as StyleOption['wordConfig'];
    }

    // Similarly for previewCss - prefer explicit override
    if (raw.previewCss) {
      previewCss = raw.previewCss;
    } else {
      previewCss = generatePreviewCss(elements, fonts, palette);
    }
  } else {
    const defaultHeading1: DocxStyleConfig = {
      font: 'Arial', size: 24, color: '000000', align: 'left', spacing: { before: 240, after: 120, line: 240 }
    };
    const defaultHeading2: DocxStyleConfig = {
      font: 'Arial', size: 18, color: '333333', align: 'left', spacing: { before: 200, after: 100, line: 240 }
    };
    const defaultBody: DocxStyleConfig = {
      font: 'Arial', size: 11, color: '333333', align: 'left', spacing: { before: 0, after: 120, line: 276 }
    };

    wordConfig = raw.wordConfig && raw.wordConfig.heading1 && raw.wordConfig.heading2 && raw.wordConfig.body
      ? {
        heading1: { ...defaultHeading1, ...raw.wordConfig.heading1 },
        heading2: { ...defaultHeading2, ...raw.wordConfig.heading2 },
        body: { ...defaultBody, ...raw.wordConfig.body },
        accentColor: raw.wordConfig.accentColor || '000000'
      }
      : {
        heading1: defaultHeading1,
        heading2: defaultHeading2,
        body: defaultBody,
        accentColor: '000000'
      };

    previewCss = raw.previewCss || 'font-family: Arial, sans-serif;';
  }

  const template: StyleOption = {
    id: raw.id,
    name: raw.name,
    category: raw.category || 'Other',
    description: raw.description || '',
    vibe: raw.vibe || '',
    googleFontsImport: raw.googleFontsImport || '',
    wordConfig,
    previewCss,
    // Preserve unified template structure if present
    ...(raw.typography && { typography: raw.typography }),
    ...(raw.elements && { elements: raw.elements }),
    ...(raw.page && { page: raw.page })
  };

  const extraFields = Object.entries(raw).reduce((acc, [key, val]) => {
    if (!['id', 'name', 'category', 'description', 'vibe', 'googleFontsImport', 'wordConfig', 'previewCss', 'typography', 'elements', 'page'].includes(key)) {
      acc[key] = val;
    }
    return acc;
  }, {} as Record<string, any>);

  return { ...template, ...extraFields };
}

/**
 * Debug function to check paths
 */
export async function debugPaths(): Promise<string> {
  try {
    return await invoke<string>('debug_paths');
  } catch (e) {
    return `Error: ${e}`;
  }
}

/**
 * Load all templates from the portable folder (next to EXE)
 * Uses Rust backend for file operations since BaseDirectory.Executable doesn't work in JS
 */
export async function loadTemplates(): Promise<{ templates: StyleOption[]; error?: string }> {
  const templates: StyleOption[] = [];
  let error: string | undefined;

  try {
    // Use Rust command to read all templates
    console.log('Calling read_templates command...');
    const files = await invoke<TemplateFile[]>('read_templates');
    console.log(`Received ${files.length} templates from Rust`);

    for (const file of files) {
      try {
        const raw = JSON.parse(file.content) as RawTemplate;
        const validated = validateTemplate(raw, file.name);
        if (validated) {
          // Use folder-based category from Rust, fallback to 'Other'
          const category = file.category || 'Other';
          templates.push({ ...validated, category });
        }
      } catch (e) {
        console.error(`Failed to parse template ${file.name}:`, e);
      }
    }

    if (templates.length === 0) {
      error = 'No templates found.';
    }
  } catch (e) {
    console.error('Error in loadTemplates:', e);
    error = e instanceof Error ? e.message : String(e);
  }

  // Sort by category then name
  templates.sort((a, b) => {
    const catCompare = a.category.localeCompare(b.category);
    if (catCompare !== 0) return catCompare;
    return a.name.localeCompare(b.name);
  });

  // Deduplicate by ID (in case of duplicate files)
  const seen = new Set<string>();
  const deduplicated = templates.filter(t => {
    if (seen.has(t.id)) {
      console.warn(`Duplicate template ID found: ${t.id}, skipping duplicate`);
      return false;
    }
    seen.add(t.id);
    return true;
  });

  console.log(`Returning ${deduplicated.length} templates (deduplicated from ${templates.length}), error: ${error}`);
  return { templates: deduplicated, error };
}

/**
 * Open the templates folder in the system file explorer
 */
export async function openTemplatesFolder(): Promise<{ success: boolean; error?: string }> {
  try {
    await invoke('open_templates_folder');
    return { success: true };
  } catch (e) {
    const errorMsg = e instanceof Error ? e.message : String(e);
    return { success: false, error: errorMsg };
  }
}

/**
 * Load a single template by ID
 */
export async function loadTemplateById(id: string): Promise<StyleOption | null> {
  const { templates } = await loadTemplates();
  return templates.find(t => t.id === id) || null;
}

/**
 * Get all available categories from templates
 */
export function getCategories(templates: StyleOption[]): string[] {
  const categories = new Set<string>();
  templates.forEach(t => categories.add(t.category));
  return Array.from(categories).sort();
}
