import type { Database } from 'sql.js';
import { RecipeRepository } from '../repositories/RecipeRepository.js';
import { TagRepository } from '../repositories/TagRepository.js';
import { CopyMeThatHtmlParser, type ParsedCopyMeThatRecipe } from './CopyMeThatHtmlParser.js';
import { CopyMeThatTxtParser, type ParsedCopyMeThatTxtRecipe } from './CopyMeThatTxtParser.js';
import type { Recipe, CreateRecipeInput } from '../types/recipe.js';

export interface ImportOptions {
  skipDuplicates?: boolean;
  importImages?: boolean;
}

export interface ImportResult {
  success: boolean;
  imported: number;
  skipped: number;
  failed: number;
  recipes: Recipe[];
  errors: string[];
}

export class CopyMeThatImportService {
  private recipeRepo: RecipeRepository;
  private tagRepo: TagRepository;
  private htmlParser: CopyMeThatHtmlParser;
  private txtParser: CopyMeThatTxtParser;

  constructor(private db: Database) {
    this.recipeRepo = new RecipeRepository(db);
    this.tagRepo = new TagRepository(db);
    this.htmlParser = new CopyMeThatHtmlParser();
    this.txtParser = new CopyMeThatTxtParser();
  }

  /**
   * Import recipes from CopyMeThat HTML export file.
   */
  async importFromHtml(html: string, options: ImportOptions = {}): Promise<ImportResult> {
    const parsed = this.htmlParser.parseRecipes(html);
    return this.processRecipes(parsed, options);
  }

  /**
   * Import recipes from multiple CopyMeThat TXT export files.
   */
  async importFromTxtFiles(txtContents: { filename: string; content: string }[], options: ImportOptions = {}): Promise<ImportResult> {
    const parsed: ParsedCopyMeThatTxtRecipe[] = [];
    
    for (const { content } of txtContents) {
      const recipe = this.txtParser.parseRecipe(content);
      if (recipe) parsed.push(recipe);
    }
    
    return this.processRecipes(parsed, options);
  }

  /**
   * Core import logic: process parsed recipes and insert into database.
   */
  private async processRecipes(
    recipes: (ParsedCopyMeThatRecipe | ParsedCopyMeThatTxtRecipe)[],
    options: ImportOptions
  ): Promise<ImportResult> {
    const result: ImportResult = {
      success: true,
      imported: 0,
      skipped: 0,
      failed: 0,
      recipes: [],
      errors: [],
    };

    // Precompute a Set of normalized keys for O(1) duplicate detection
    const existingRecipes = this.recipeRepo.findAll({ limit: 10000 });
    const existingKeys = new Set<string>();
    for (const r of existingRecipes) {
      const key = `${r.title.toLowerCase()}|${r.source_url ?? ''}`;
      existingKeys.add(key);
    }

    for (const parsedRecipe of recipes) {
      try {
        // Check for duplicates
        if (options.skipDuplicates) {
          const key = `${parsedRecipe.title.toLowerCase()}|${parsedRecipe.sourceUrl ?? ''}`;
          if (existingKeys.has(key)) {
            result.skipped++;
            continue;
          }
        }

        // Get or create tags
        const tagIds: number[] = [];
        if ('tags' in parsedRecipe && parsedRecipe.tags.length > 0) {
          for (const tagName of parsedRecipe.tags) {
            let tag = this.tagRepo.findByName(tagName);
            if (!tag) {
              tag = this.tagRepo.create({ name: tagName });
            }
            tagIds.push(tag.id);
          }
        }

        // Convert to CreateRecipeInput
        let input: CreateRecipeInput;
        if ('description' in parsedRecipe) {
          // HTML format has more fields
          input = this.htmlParser.toCreateRecipeInput(parsedRecipe as ParsedCopyMeThatRecipe);
        } else {
          // TXT format
          input = this.txtParser.toCreateRecipeInput(parsedRecipe as ParsedCopyMeThatTxtRecipe);
        }
        
        input.tagIds = tagIds;

        // Create recipe
        const created = this.recipeRepo.create(input);
        result.recipes.push(created);
        result.imported++;
      } catch (error) {
        result.failed++;
        const errorMsg = error instanceof Error ? error.message : 'Unknown error';
        result.errors.push(`Failed to import "${parsedRecipe.title}": ${errorMsg}`);
        console.error(`Import error for "${parsedRecipe.title}":`, error);
      }
    }

    if (result.failed > 0) {
      result.success = false;
    }

    return result;
  }

  /**
   * Validate and clean an image URL path from CopyMeThat export.
   */
  private cleanImageUrl(imageUrl: string | undefined): string | undefined {
    if (!imageUrl) return undefined;
    
    // If it's a relative path (images/...), we'll need to handle image uploads separately
    // For now, return undefined for relative paths
    if (imageUrl.startsWith('images/')) {
      return undefined;
    }
    
    // If it's an absolute URL, return as-is
    if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
      return imageUrl;
    }
    
    return undefined;
  }
}
