'use server';

import { BottleMetadataSchema, BottleMetadata } from '@/types/whisky';
import { createClient } from '@/lib/supabase/server';
import { trackApiUsage } from '@/services/track-api-usage';
import { checkCreditBalance, deductCredits } from '@/services/credit-service';
import { getAIProvider, getOpenRouterClient, OPENROUTER_VISION_MODEL, OPENROUTER_PROVIDER_PREFERENCES } from '@/lib/openrouter';
import { normalizeWhiskyData } from '@/lib/distillery-matcher';
import { formatWhiskyName } from '@/utils/formatWhiskyName';
import { createHash } from 'crypto';

const VISION_PROMPT = `ROLE: Senior Whisky Database Curator.

OBJECTIVE: Extract metadata from the bottle image.
CRITICAL: You must CONSTRUCT the product name from its parts, not just read lines.

INPUT IMAGE ANALYSIS (Mental Steps):
1. FIND DISTILLERY: Look for the most prominent brand name (e.g. "Annandale").
2. FIND AGE: Scan the center for "Aged X Years" or large numbers. (In this image: Look for a large "10" in the center).
3. FIND VINTAGE: Look for small script/cursive text like "Distilled 2011".
4. FIND CASK TYPE: Look for specific maturation terms like 'Sherry', 'Bourbon', 'Port', 'Oloroso', 'PX', 'Madeira', 'Rum', 'Hogshead', 'Butt', 'Barrel', or 'Finish'. Extract ONLY this phrase into this field (e.g., 'Oloroso Cask Matured') cask_type. Do not leave null if these words are visible. 
5. FIND SERIES: Look at the top logo (e.g. "Cadenhead's Natural Strength").

COMPOSITION RULES (How to fill the 'name' field):
- DO NOT just write "Single Malt".
- Format: "[Age/Vintage] [Series] [Cask Info]"
- Example: "10 Year Old Cadenhead's Natural Strength Oloroso Matured"

OUTPUT SCHEMA (Strict JSON):
{
  "name": "string (The constructed full name based on rules above)",
  "distillery": "string",
  "bottler": "string",
  "series": "string (e.g. Natural Strength)",
  "abv": number,
  "age": numberOrNull,
  "vintage": "stringOrNull",
  "cask_type": "stringOrNull",
  "distilled_at": "stringOrNull",
  "bottled_at": "stringOrNull",
  "batch_info": "stringOrNull",
  "is_whisky": true,
  "confidence": number
}`;

export interface ScannerResult {
    success: boolean;
    data?: BottleMetadata;
    error?: string;
    provider?: 'openrouter';
    perf?: {
        imagePrep?: number;
        apiCall: number;
        total: number;
        cacheHit?: boolean;
        apiDuration?: number;
        parsing?: number;
        parseDuration?: number;
        uploadSize?: number;
        cacheCheck?: number;
        encoding?: number;
        modelInit?: number;
        validation?: number;
        dbOps?: number;
    };
    raw?: any;
    search_string?: string;
}

/**
 * Compatibility wrapper for older call sites that use an object/FormData input.
 */
export async function scanLabel(input: any): Promise<ScannerResult> {
    const getValue = (obj: any, key: string): any => {
        if (obj && typeof obj.get === 'function') return obj.get(key);
        if (obj && typeof obj[key] !== 'undefined') return obj[key];
        return null;
    };

    const file = getValue(input, 'file');
    if (file && file instanceof File) {
        // Handle file input (e.g. from FormData)
        const arrayBuffer = await file.arrayBuffer();
        const base64 = Buffer.from(arrayBuffer).toString('base64');
        return analyzeBottleLabel(`data:${file.type};base64,${base64}`);
    }

    if (typeof input === 'string') {
        return analyzeBottleLabel(input);
    }

    return { success: false, error: 'Ungültiges Eingabeformat.' };
}

/**
 * Unified action for analyzing a whisky bottle label.
 * Replaces redundant gemini-vision.ts, scan-label.ts, and analyze-bottle.ts.
 */
export async function analyzeBottleLabel(imageBase64: string): Promise<ScannerResult> {
    const startTotal = performance.now();
    const provider = getAIProvider();

    if (!imageBase64 || imageBase64.length < 100) {
        return { success: false, error: 'Ungültige Bilddaten.' };
    }

    try {
        // 1. Auth & Credit Check
        const supabase = await createClient();
        const { data: { user } } = await supabase.auth.getUser();
        if (!user) return { success: false, error: 'Nicht autorisiert.' };

        const creditCheck = await checkCreditBalance(user.id, 'gemini_ai');
        if (!creditCheck.allowed) {
            return {
                success: false,
                error: `Nicht genügend Credits. Benötigt: ${creditCheck.cost}, Verfügbar: ${creditCheck.balance}.`
            };
        }

        // 2. Extract base64 and hash for caching
        let base64Data = imageBase64;
        let mimeType = 'image/webp';
        if (imageBase64.startsWith('data:')) {
            const matches = imageBase64.match(/^data:([^;]+);base64,(.+)$/);
            if (matches) {
                mimeType = matches[1];
                base64Data = matches[2];
            }
        }

        const buffer = Buffer.from(base64Data, 'base64');
        const imageHash = createHash('sha256').update(buffer).digest('hex');

        // 3. Cache Check
        const { data: cachedResult } = await supabase
            .from('vision_cache')
            .select('result')
            .eq('hash', imageHash)
            .maybeSingle();

        if (cachedResult) {
            console.log(`[Scanner] Cache HIT for hash: ${imageHash.slice(0, 8)}...`);
            return {
                success: true,
                data: cachedResult.result as BottleMetadata,
                perf: {
                    apiCall: 0,
                    total: performance.now() - startTotal,
                    cacheHit: true
                }
            };
        }

        // 4. AI Analysis with retry logic for OpenRouter
        console.log(`[Scanner] Using provider: ${provider}`);
        let aiResult: { data: any; apiTime: number; responseText: string };

        const client = getOpenRouterClient();
        const startApi = performance.now();
        const maxRetries = 3;
        let lastError: any = null;
        let response: any = null;

        for (let attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                response = await client.chat.completions.create({
                    model: OPENROUTER_VISION_MODEL,
                    messages: [
                        {
                            role: 'user',
                            content: [
                                { type: 'image_url', image_url: { url: `data:${mimeType};base64,${base64Data}` } },
                                { type: 'text', text: VISION_PROMPT },
                            ],
                        },
                    ],
                    temperature: 0.1,
                    max_tokens: 1024,
                    // @ts-ignore
                    provider: OPENROUTER_PROVIDER_PREFERENCES,
                });
                break; // Success!
            } catch (err: any) {
                lastError = err;
                if (err.status === 429 && attempt < maxRetries) {
                    const delay = Math.pow(2, attempt) * 1000;
                    console.warn(`[Scanner] Rate limited (429). Retrying in ${delay}ms...`);
                    await new Promise(resolve => setTimeout(resolve, delay));
                    continue;
                }
                throw err;
            }
        }

        if (!response) throw lastError || new Error('OpenRouter response failed after retries');

        const content = response.choices[0]?.message?.content || '{}';
        let jsonStr = content;
        const jsonMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/) || content.match(/\{[\s\S]*\}/);
        if (jsonMatch) {
            jsonStr = jsonMatch[jsonMatch.length - 1].trim();
        }
        aiResult = {
            data: JSON.parse(jsonStr),
            apiTime: performance.now() - startApi,
            responseText: content
        };

        // 6. Name Composition & Normalization
        // Use standardized helper to construct the perfect name
        console.log(`[Uncleaned Data]: ${JSON.stringify(aiResult.data)}`);

        const d = aiResult.data;
        const constructedName = formatWhiskyName({
            distillery: d.distillery || '',
            bottler: d.bottler,
            series: d.series,
            age: d.age,
            vintage: d.vintage,
            cask_type: d.cask_type
        }) || d.name;

        // Validation & Normalization
        const validatedData = BottleMetadataSchema.parse({
            ...d,
            name: constructedName
        });

        const normalized = normalizeWhiskyData(
            validatedData.name || '',
            validatedData.distillery || ''
        );

        const finalData = {
            ...validatedData,
            name: normalized.name || validatedData.name,
            distillery: normalized.distillery || validatedData.distillery,
        };

        // 7. Success Tracking & Caching
        await trackApiUsage({
            userId: user.id,
            apiType: 'gemini_ai',
            endpoint: `analyzeBottleLabel_${provider}`,
            success: true,
            provider,
            model: OPENROUTER_VISION_MODEL,
            responseText: aiResult.responseText
        });
        await deductCredits(user.id, 'gemini_ai', `Scanner analysis (${provider})`);

        await supabase.from('vision_cache').insert({ hash: imageHash, result: finalData });

        return {
            success: true,
            data: finalData,
            provider,
            perf: {
                apiCall: aiResult.apiTime,
                apiDuration: aiResult.apiTime, // Compatibility
                total: performance.now() - startTotal,
                cacheHit: false
            }
        };

    } catch (error: any) {
        console.error(`[Scanner] Analysis failed:`, error);
        return {
            success: false,
            error: error.message || 'Vision analysis failed.',
        };
    }
}
