'use client';

/**
 * Cascade OCR Service
 * 
 * Waterfall-Prinzip:
 * 1. Native TextDetector API (Chrome)
 * 2. RegEx für Hard Facts (ABV, Age, Vintage, etc.)
 * 3. Fuzzy Match für Distillery
 * 4. window.ai für Deduktion (falls vorhanden)
 * 5. Fallback: Raw Text
 */

import { FEATURES } from '@/config/features';
import { normalizeDistillery } from '@/lib/distillery-matcher';
import { saveOcrLog } from '@/services/save-ocr-log';

// Types
export interface CascadeOCRResult {
    success: boolean;
    // Extracted fields
    distillery: string | null;
    name: string | null;
    abv: number | null;
    age: number | null;
    vintage: string | null;
    volume: string | null;
    category: string | null;
    // Meta
    rawText: string;
    matchSources: {
        distillery: 'fuzzy' | 'ai' | 'manual' | null;
        abv: 'regex' | null;
        age: 'regex' | null;
    };
    confidence: number;
    processingTimeMs?: number;
    savedToDb?: boolean;
}


// RegEx patterns for whisky bottle labels
const PATTERNS = {
    // ABV: "40%", "40% vol", "40.5%", "40,5%"
    abv: /(\d{1,2}[.,]\d{1}|\d{1,2})\s*%\s*(?:vol|alc)?/i,

    // Age: "10 Years", "12 Year Old", "10yo", "10 YO"
    age: /(\d{1,2})\s*(?:years?|yo|y\.?o\.?|jahre?)\s*(?:old)?/i,

    // Vintage: "Distilled 2010", "2010", "Vintage 2015"
    vintage: /(?:distilled|vintage|dist\.?)\s*(\d{4})|^(\d{4})$/im,

    // Volume: "700ml", "70cl", "750ml"
    volume: /(\d{2,4})\s*(?:ml|cl)/i,

    // Cask Strength indicator
    caskStrength: /cask\s*strength|fass\s*st[aä]rke|natural\s*strength/i,

    // Single Malt indicator
    singleMalt: /single\s*malt/i,

    // Blend indicator
    blend: /blended|blend/i,
};

/**
 * Step 1: Native OCR via TextDetector API
 */
async function detectText(imageBlob: Blob): Promise<string[]> {
    // Check if TextDetector is available (Chrome only)
    if (!('TextDetector' in window)) {
        console.log('[CascadeOCR] TextDetector not available');
        return [];
    }

    try {
        // @ts-ignore - TextDetector is experimental
        const detector = new window.TextDetector();
        const imageBitmap = await createImageBitmap(imageBlob);
        const detections = await detector.detect(imageBitmap);

        const texts = detections.map((d: any) => d.rawValue).filter(Boolean);
        console.log('[CascadeOCR] TextDetector found:', texts);
        return texts;
    } catch (err) {
        console.warn('[CascadeOCR] TextDetector failed:', err);
        return [];
    }
}

/**
 * Step 2: Extract hard facts via RegEx
 */
function extractHardFacts(text: string): {
    abv: number | null;
    age: number | null;
    vintage: string | null;
    volume: string | null;
    category: string | null;
} {
    const result = {
        abv: null as number | null,
        age: null as number | null,
        vintage: null as string | null,
        volume: null as string | null,
        category: null as string | null,
    };

    // ABV
    const abvMatch = text.match(PATTERNS.abv);
    if (abvMatch) {
        result.abv = parseFloat(abvMatch[1].replace(',', '.'));
        console.log('[CascadeOCR] RegEx ABV:', result.abv);
    }

    // Age
    const ageMatch = text.match(PATTERNS.age);
    if (ageMatch) {
        result.age = parseInt(ageMatch[1], 10);
        console.log('[CascadeOCR] RegEx Age:', result.age);
    }

    // Vintage
    const vintageMatch = text.match(PATTERNS.vintage);
    if (vintageMatch) {
        result.vintage = vintageMatch[1] || vintageMatch[2];
        console.log('[CascadeOCR] RegEx Vintage:', result.vintage);
    }

    // Volume
    const volumeMatch = text.match(PATTERNS.volume);
    if (volumeMatch) {
        result.volume = volumeMatch[0];
        console.log('[CascadeOCR] RegEx Volume:', result.volume);
    }

    // Category
    if (PATTERNS.singleMalt.test(text)) {
        result.category = 'Single Malt';
    } else if (PATTERNS.blend.test(text)) {
        result.category = 'Blended';
    }
    if (result.category) {
        console.log('[CascadeOCR] RegEx Category:', result.category);
    }

    return result;
}

/**
 * Step 3a: Fuzzy match distillery
 */
function matchDistillery(textLines: string[]): { name: string; matched: boolean } | null {
    // Try each line as a potential distillery name
    for (const line of textLines) {
        if (line.length < 3 || line.length > 50) continue;

        const result = normalizeDistillery(line);
        if (result.matched) {
            console.log('[CascadeOCR] Fuzzy Distillery Match:', result.name);
            return { name: result.name, matched: true };
        }
    }
    return null;
}

/**
 * Step 3b: Use window.ai for deduction (if available)
 */
async function deduceWithWindowAI(rawText: string): Promise<{
    distillery: string | null;
    name: string | null;
    category: string | null;
}> {
    // Check if window.ai is available
    // @ts-ignore
    if (!window.ai || !window.ai.languageModel) {
        console.log('[CascadeOCR] window.ai not available');
        return { distillery: null, name: null, category: null };
    }

    try {
        console.log('[CascadeOCR] Using window.ai for deduction...');

        // @ts-ignore
        const session = await window.ai.languageModel.create();

        const prompt = `Analyze this text from a whisky bottle label and extract:
1. Distillery name (the producer)
2. Bottle name/expression
3. Category (Single Malt, Blended, Bourbon, etc.)

Text: "${rawText}"

Respond in JSON format only:
{"distillery": "...", "name": "...", "category": "..."}`;

        const response = await session.prompt(prompt);
        console.log('[CascadeOCR] window.ai response:', response);

        try {
            const parsed = JSON.parse(response);
            return {
                distillery: parsed.distillery || null,
                name: parsed.name || null,
                category: parsed.category || null,
            };
        } catch {
            return { distillery: null, name: null, category: null };
        }
    } catch (err) {
        console.warn('[CascadeOCR] window.ai failed:', err);
        return { distillery: null, name: null, category: null };
    }
}

/**
 * Main cascade function
 */
export async function runCascadeOCR(imageBlob: Blob): Promise<CascadeOCRResult> {
    if (!FEATURES.ENABLE_CASCADE_OCR) {
        console.log('[CascadeOCR] Feature disabled');
        return {
            success: false,
            distillery: null,
            name: null,
            abv: null,
            age: null,
            vintage: null,
            volume: null,
            category: null,
            rawText: '',
            matchSources: { distillery: null, abv: null, age: null },
            confidence: 0,
        };
    }

    console.log('[CascadeOCR] === Starting Cascade OCR ===');
    const startTime = performance.now();

    // Step 1: Native OCR
    const textLines = await detectText(imageBlob);

    const rawText = textLines.join('\n');
    console.log('[CascadeOCR] Raw text:', rawText);

    if (!rawText.trim()) {
        console.log('[CascadeOCR] No text detected');

        // Still save to DB for debugging (shows TextDetector availability)
        const processingTimeMs = performance.now() - startTime;
        try {
            await saveOcrLog({
                rawText: '',
                detectedTexts: [],
                confidence: 0,
                deviceInfo: navigator.userAgent,
                ocrMethod: 'TextDetector' in window ? 'text_detector' : 'not_supported',
                processingTimeMs: Math.round(processingTimeMs),
            });
            console.log('[CascadeOCR] Empty result logged to DB');
        } catch (err) {
            console.warn('[CascadeOCR] Failed to log empty result:', err);
        }

        return {
            success: false,
            distillery: null,
            name: null,
            abv: null,
            age: null,
            vintage: null,
            volume: null,
            category: null,
            rawText: '',
            matchSources: { distillery: null, abv: null, age: null },
            confidence: 0,
        };
    }


    // Step 2: Extract hard facts via RegEx
    const hardFacts = extractHardFacts(rawText);

    // Step 3a: Fuzzy match distillery
    let distilleryResult = matchDistillery(textLines);
    let distillerySource: 'fuzzy' | 'ai' | 'manual' | null = distilleryResult?.matched ? 'fuzzy' : null;

    // Step 3b: If no fuzzy match, try window.ai
    let aiResult = { distillery: null as string | null, name: null as string | null, category: null as string | null };
    if (!distilleryResult) {
        aiResult = await deduceWithWindowAI(rawText);
        if (aiResult.distillery) {
            distilleryResult = { name: aiResult.distillery, matched: false };
            distillerySource = 'ai';
        }
    }

    // Calculate confidence
    let confidence = 0;
    if (distilleryResult?.matched) confidence += 40;
    else if (distilleryResult) confidence += 20;
    if (hardFacts.abv) confidence += 20;
    if (hardFacts.age) confidence += 20;
    if (hardFacts.category || aiResult.category) confidence += 10;
    if (hardFacts.vintage) confidence += 10;

    const processingTimeMs = performance.now() - startTime;

    const result: CascadeOCRResult = {
        success: true,
        distillery: distilleryResult?.name || null,
        name: aiResult.name || null,
        abv: hardFacts.abv,
        age: hardFacts.age,
        vintage: hardFacts.vintage,
        volume: hardFacts.volume,
        category: hardFacts.category || aiResult.category || null,
        rawText,
        matchSources: {
            distillery: distillerySource,
            abv: hardFacts.abv ? 'regex' : null,
            age: hardFacts.age ? 'regex' : null,
        },
        confidence,
        processingTimeMs,
        savedToDb: false,
    };

    console.log('[CascadeOCR] === Final Result ===');
    console.log('[CascadeOCR] Distillery:', result.distillery, `(${result.matchSources.distillery})`);
    console.log('[CascadeOCR] Name:', result.name);
    console.log('[CascadeOCR] ABV:', result.abv, `(${result.matchSources.abv})`);
    console.log('[CascadeOCR] Age:', result.age, `(${result.matchSources.age})`);
    console.log('[CascadeOCR] Vintage:', result.vintage);
    console.log('[CascadeOCR] Volume:', result.volume);
    console.log('[CascadeOCR] Category:', result.category);
    console.log('[CascadeOCR] Confidence:', result.confidence + '%');
    console.log('[CascadeOCR] Processing Time:', processingTimeMs.toFixed(0) + 'ms');

    // Save to database (async, non-blocking)
    try {
        // Create thumbnail for DB storage
        let imageThumbnail: string | undefined;
        try {
            const bitmap = await createImageBitmap(imageBlob);
            const canvas = document.createElement('canvas');
            const maxSize = 200;
            const scale = Math.min(maxSize / bitmap.width, maxSize / bitmap.height);
            canvas.width = bitmap.width * scale;
            canvas.height = bitmap.height * scale;
            const ctx = canvas.getContext('2d');
            if (ctx) {
                ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
                imageThumbnail = canvas.toDataURL('image/jpeg', 0.7);
            }
        } catch (thumbErr) {
            console.warn('[CascadeOCR] Thumbnail creation failed:', thumbErr);
        }

        const saveResult = await saveOcrLog({
            imageThumbnail,
            rawText: result.rawText,
            detectedTexts: textLines,
            distillery: result.distillery,
            distillerySource: result.matchSources.distillery,
            bottleName: result.name,
            abv: result.abv,
            age: result.age,
            vintage: result.vintage,
            volume: result.volume,
            category: result.category,
            confidence: result.confidence,
            deviceInfo: navigator.userAgent,
            ocrMethod: 'TextDetector' in window ? 'text_detector' : 'fallback',
            processingTimeMs: Math.round(processingTimeMs),
        });

        if (saveResult.success) {
            result.savedToDb = true;
            console.log('[CascadeOCR] Saved to DB:', saveResult.id);
        } else {
            console.warn('[CascadeOCR] DB save failed:', saveResult.error);
        }
    } catch (dbErr) {
        console.error('[CascadeOCR] DB save error:', dbErr);
    }

    return result;
}


/**
 * Hook to use cascade OCR in components
 */
export function useCascadeOCR() {
    const processImage = async (imageBlob: Blob) => {
        return runCascadeOCR(imageBlob);
    };

    return { processImage };
}
