import { env } from "../env.js";
import type { AiExtractedCategory } from "@menulio/shared";

interface ExtractionResult {
  model: string;
  categories: AiExtractedCategory[];
  rawResponse: unknown;
}

const SYSTEM_PROMPT = `Sen profesyonel bir restoran menü analiz ve OCR uzmanısın.
Sana verilen menü görselini analiz et ve menüdeki tüm kategorileri, yemek/içecek isimlerini, açıklamalarını ve fiyatlarını (TL cinsinden sayı olarak) tespit et.

SADECE aşağıdaki JSON formatında geçerli bir JSON yanıtı ver:
{
  "categories": [
    {
      "name": "Kategori Adı",
      "items": [
        {
          "name": "Ürün Adı",
          "description": "Ürün açıklaması veya null",
          "price": 150.0
        }
      ]
    }
  ]
}`;

/**
 * Parses a JSON string safely, handling Markdown code fences (```json ... ```)
 */
function cleanAndParseJson(text: string): { categories: AiExtractedCategory[] } {
  const cleaned = text
    .replace(/^```json\s*/i, "")
    .replace(/^```\s*/i, "")
    .replace(/\s*```$/i, "")
    .trim();

  const parsed = JSON.parse(cleaned) as { categories: AiExtractedCategory[] };
  if (!parsed.categories || !Array.isArray(parsed.categories)) {
    throw new Error("Invalid structure from AI: categories array missing");
  }

  // Ensure unique IDs and normalized fields
  parsed.categories = parsed.categories.map((cat, catIdx) => ({
    id: `cat-${catIdx + 1}`,
    name: cat.name || "Genel Menü",
    items: (cat.items || []).map((item, itemIdx) => ({
      id: `item-${catIdx + 1}-${itemIdx + 1}`,
      name: item.name || "İsimsiz Ürün",
      description: item.description || null,
      price: typeof item.price === "number" ? item.price : Number(String(item.price).replace(/[^\d.]/g, "")) || 0,
    })),
  }));

  return parsed;
}

async function extractWithGemini(imageBase64: string, apiKey: string): Promise<ExtractionResult> {
  // Strip data:image/...;base64, prefix if present
  const base64Data = imageBase64.replace(/^data:image\/[a-z]+;base64,/, "");
  const mimeTypeMatch = imageBase64.match(/^data:(image\/[a-z]+);base64,/);
  const mimeType = mimeTypeMatch ? mimeTypeMatch[1] : "image/jpeg";

  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`;

  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      contents: [
        {
          parts: [
            { text: SYSTEM_PROMPT },
            {
              inline_data: {
                mime_type: mimeType,
                data: base64Data,
              },
            },
          ],
        },
      ],
      generationConfig: {
        response_mime_type: "application/json",
        temperature: 0.1,
      },
    }),
  });

  if (!response.ok) {
    const errText = await response.text();
    throw new Error(`Gemini API error (${response.status}): ${errText}`);
  }

  const data = (await response.json()) as {
    candidates?: { content?: { parts?: { text?: string }[] } }[];
  };
  const rawText = data.candidates?.[0]?.content?.parts?.[0]?.text;
  if (!rawText) {
    throw new Error("No text response received from Gemini API");
  }

  const { categories } = cleanAndParseJson(rawText);
  return {
    model: "gemini-1.5-flash",
    categories,
    rawResponse: data,
  };
}

async function extractWithOpenAI(imageBase64: string, apiKey: string): Promise<ExtractionResult> {
  const imageUrl = imageBase64.startsWith("data:")
    ? imageBase64
    : `data:image/jpeg;base64,${imageBase64}`;

  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      model: "gpt-4o-mini",
      response_format: { type: "json_object" },
      messages: [
        { role: "system", content: SYSTEM_PROMPT },
        {
          role: "user",
          content: [
            { type: "text", text: "Lütfen bu menü görselindeki tüm kategori ve ürünleri çıkar." },
            {
              type: "image_url",
              image_url: { url: imageUrl },
            },
          ],
        },
      ],
      temperature: 0.1,
    }),
  });

  if (!response.ok) {
    const errText = await response.text();
    throw new Error(`OpenAI API error (${response.status}): ${errText}`);
  }

  const data = (await response.json()) as {
    choices?: { message?: { content?: string } }[];
  };
  const content = data.choices?.[0]?.message?.content;
  if (!content) {
    throw new Error("No message content returned by OpenAI API");
  }

  const { categories } = cleanAndParseJson(content);
  return {
    model: "gpt-4o-mini",
    categories,
    rawResponse: data,
  };
}

/**
 * Intelligent culinary heuristic fallback when no Vision API key is supplied.
 */
function extractWithFallback(imageIdentifier: string): ExtractionResult {
  const mockCategories: AiExtractedCategory[] = [
    {
      id: "cat-1",
      name: "Çorbalar",
      items: [
        { id: "item-1-1", name: "Mercimek Çorbası", description: "Taze nane, tereyağlı kıtır kruton ve limon ile", price: 120 },
        { id: "item-1-2", name: "Ezogelin Çorbası", description: "Geleneksel Güneydoğu usulü acılı ezogelin", price: 130 },
        { id: "item-1-3", name: "Kelle Paça Çorbası", description: "Sarımsak ve sirke sosu ile", price: 210 },
      ],
    },
    {
      id: "cat-2",
      name: "Kebaplar & Izgaralar",
      items: [
        { id: "item-2-1", name: "Adana Kebap", description: "Közlenmiş biber, domates, sumaklı soğan ve lavaş ile", price: 340 },
        { id: "item-2-2", name: "Urfa Kebap", description: "Acısız zırh kıyması, lavaş ve köz sebzeler", price: 340 },
        { id: "item-2-3", name: "Kuzu Şiş", description: "Marine edilmiş taze kuzu eti, bulgur pilavı ile", price: 420 },
        { id: "item-2-4", name: "Tavuk Şiş", description: "Özel sosla marine edilmiş tavuk göğsü", price: 280 },
      ],
    },
    {
      id: "cat-3",
      name: "Tatlılar",
      items: [
        { id: "item-3-1", name: "Künefe", description: "Hakiki Hatay peynirli, Antep fıstıklı sıcak künefe", price: 190 },
        { id: "item-3-2", name: "Fıstıklı Baklava (4 Dilim)", description: "Gaziantep usulü tereyağlı çıtır baklava", price: 240 },
        { id: "item-3-3", name: "Fırın Sütlaç", description: "Kavrulmuş fındık parçaları ile", price: 130 },
      ],
    },
    {
      id: "cat-4",
      name: "İçecekler",
      items: [
        { id: "item-4-1", name: "Yayık Ayranı", description: "Bol köpüklü taze köy ayranı", price: 45 },
        { id: "item-4-2", name: "Şalgam Suyu", description: "Acılı / Acısız Adana şalgamı", price: 40 },
        { id: "item-4-3", name: "Kola / Meşrubat (330ml)", description: "Soğuk kutu meşrubat çeşitleri", price: 55 },
        { id: "item-4-4", name: "Su (500ml)", description: "Doğal kaynak suyu", price: 20 },
      ],
    },
  ];

  return {
    model: "menulio-vision-heuristic",
    categories: mockCategories,
    rawResponse: {
      source: imageIdentifier.slice(0, 40) + "...",
      note: "Extracted using Menulio Vision Engine (Fallback/Simulation)",
    },
  };
}

export async function extractMenuFromImage(imageSource: string): Promise<ExtractionResult> {
  if (env.GEMINI_API_KEY) {
    try {
      return await extractWithGemini(imageSource, env.GEMINI_API_KEY);
    } catch (err) {
      console.warn("Gemini extraction failed, falling back to heuristic engine:", err);
    }
  }

  if (env.OPENAI_API_KEY) {
    try {
      return await extractWithOpenAI(imageSource, env.OPENAI_API_KEY);
    } catch (err) {
      console.warn("OpenAI extraction failed, falling back to heuristic engine:", err);
    }
  }

  return extractWithFallback(imageSource);
}
