import OpenAI from "openai";
import { GoogleGenerativeAI } from "@google/generative-ai";

let openaiClient: OpenAI | null = null;
let geminiClient: GoogleGenerativeAI | null = null;

function getOpenAIClient() {
  const apiKey = process.env.OPENAI_API_KEY;
  if (!apiKey) throw new Error("OPENAI_API_KEY não configurada no backend.");
  if (!openaiClient) openaiClient = new OpenAI({ apiKey });
  return openaiClient;
}

function getGeminiClient() {
  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey) throw new Error("GEMINI_API_KEY não configurada no backend.");
  if (!geminiClient) geminiClient = new GoogleGenerativeAI(apiKey);
  return geminiClient;
}

function getProvider() {
  const raw = (process.env.IA_PROVIDER ?? "gemini").toLowerCase().trim();
  return raw === "openai" ? "openai" : "gemini";
}

function getGeminiModelName() {
  const raw = (
    process.env.IA_GEMINI_MODEL ??
    process.env.GEMINI_MODEL ??
    "gemini-2.5-flash-lite"
  )
    .trim()
    .toLowerCase();

  if (
    raw === "gemini-1.5-flash-lite" ||
    raw === "gemini-1.5-flash-lite-latest"
  ) {
    return "gemini-2.5-flash-lite";
  }

  return raw;
}

async function gerarDescricaoComGemini(prompt: string) {
  const model = getGeminiClient().getGenerativeModel({
    model: getGeminiModelName(),
  });

  const result = await model.generateContent({
    contents: [{ role: "user", parts: [{ text: prompt }] }],
    generationConfig: {
      maxOutputTokens: 120,
      temperature: 0.2,
    },
  });

  return result.response.text().trim();
}

async function gerarDescricaoComOpenAI(prompt: string) {
  const completion = await getOpenAIClient().chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: prompt }],
    max_tokens: 120,
  });

  return (completion.choices[0]?.message?.content ?? "").trim();
}

function normalizeInput(s: string) {
  return (s ?? "").toString().trim();
}

function buildPrompt(nome: string, categoria: string, caracteristicas: string) {
  const nomeOk = normalizeInput(nome);
  const categoriaOk = normalizeInput(categoria);
  const caracteristicasOk = normalizeInput(caracteristicas);

  return `
Gere uma descrição curta, objetiva e profissional sobre o produto abaixo.
Não crie título e não invente informações.
Produto: ${nomeOk}
Categoria: ${categoriaOk}
Características: ${caracteristicasOk}
`.trim();
}

export type IAProvider = "gemini" | "openai";

export function getIAProvider(): IAProvider {
  return getProvider();
}

export function getIAModelName(): string {
  return getProvider() === "openai" ? "gpt-4o-mini" : getGeminiModelName();
}

export type QuoteStatus = "draft" | "sent" | "approved" | "rejected" | "production" | "delivered";

export interface IAQuoteItemDraft {
  title: string;
  description?: string | null;
  unit_type?: string | null;
  width_m?: number | null;
  height_m?: number | null;
  length_m?: number | null;
  quantity?: number | null;
  unit_price?: number | null;
  unit_cost?: number | null;
}

export interface IAQuoteDraft {
  client_query: string;
  client_whatsapp?: string | null;
  status?: QuoteStatus | null;
  title?: string | null;
  notes?: string | null;
  expires_at?: string | null;
  delivery_date?: string | null;
  items: IAQuoteItemDraft[];
}

export interface IAQuoteInput {
  instruction?: string | null;
  imageDataUrl?: string | null;
}

function extractJsonObject(text: string) {
  const raw = (text ?? "").toString().trim();
  if (!raw) throw new Error("Resposta vazia do provedor de IA.");
  const start = raw.indexOf("{");
  const end = raw.lastIndexOf("}");
  if (start === -1 || end === -1 || end <= start) {
    throw new Error("Não foi possível extrair JSON da resposta do provedor de IA.");
  }
  return raw.slice(start, end + 1);
}

function normalizeQuoteStatus(value: unknown): QuoteStatus | null {
  if (typeof value !== "string") return null;
  const v = value.toLowerCase().trim();
  if (v === "draft" || v === "sent" || v === "approved" || v === "rejected" || v === "production" || v === "delivered") {
    return v;
  }
  if (v === "rascunho") return "draft";
  if (v === "enviado") return "sent";
  if (v === "aprovado") return "approved";
  if (v === "recusado" || v === "rejeitado") return "rejected";
  if (v === "produção" || v === "producao" || v === "em produção" || v === "em producao") return "production";
  if (v === "entregue") return "delivered";
  return null;
}

function buildQuotePrompt(instruction: string, todayIsoDate: string) {
  const pedidoTexto = instruction.trim() || "(sem texto digitado; use a imagem anexada como fonte principal)";
  return `
Você é um assistente para criar orçamentos em um sistema.
Você pode receber:
- texto digitado livremente;
- mensagem copiada do WhatsApp;
- print da conversa ou do pedido do cliente.

Extraia do pedido do usuário um JSON estrito, sem markdown e sem texto fora do JSON.

Regras:
- Não invente preços. Se não houver preço/custo, use null.
- Se houver tamanho do item, converta para metros (ex.: 10cm = 0.1).
- Se houver prazo de entrega estipulado ou solicitado (ex: "para amanhã", "dia 25", "consegue entregar tal dia?"), interprete e retorne em "delivery_date" em formato ISO (YYYY-MM-DD) com base no "Hoje é {hoje}".
- Use "notes" apenas para observações descritivas relevantes e não para datas de entrega.
- Status permitido: draft, sent, approved, rejected, production, delivered.
- Sempre preencha "client_query" com o nome do cliente identificado no texto/imagem (ex: no cabeçalho da conversa do WhatsApp). Se não houver nome, use string vazia.
- Sempre gere ao menos 1 item em "items".
- Em conversas de WhatsApp, priorize o que o cliente pediu e ignore saudações, respostas do vendedor e trechos irrelevantes.
- Tente extrair o número de telefone/WhatsApp do cliente da imagem ou do texto fornecido. Retorne-o na propriedade "client_whatsapp" apenas com números (ex: 5511999999999).
- Se houver múltiplos itens listados (ex: "quero 2 faixas e 3 placas"), gere múltiplos objetos dentro do array "items".
- Se existir imagem anexada, use a imagem como fonte de verdade para entender itens, medidas, quantidades e observações.

Formato JSON:
{
  "client_query": "string",
  "client_whatsapp": "string|null",
  "status": "draft|sent|approved|rejected|production|delivered|null",
  "title": "string|null",
  "notes": "string|null",
  "expires_at": "YYYY-MM-DD|null",
  "delivery_date": "YYYY-MM-DD|null",
  "items": [
    {
      "title": "string",
      "description": "string|null",
      "unit_type": "unit|square_meter|linear_meter|meter|box|ream|null",
      "width_m": number|null,
      "height_m": number|null,
      "length_m": number|null,
      "quantity": number|null,
      "unit_price": number|null,
      "unit_cost": number|null
    }
  ]
}

Hoje: ${todayIsoDate}
Pedido do usuário: ${pedidoTexto}
`.trim();
}

async function gerarRascunhoOrcamentoComGemini(prompt: string, imageDataUrl?: string | null) {
  const model = getGeminiClient().getGenerativeModel({
    model: getGeminiModelName(),
  });

  const parts: Array<
    | { text: string }
    | {
        inlineData: {
          mimeType: string;
          data: string;
        };
      }
  > = [{ text: prompt }];

  if (imageDataUrl) {
    const imageMatch = /^data:(image\/[a-zA-Z0-9.+-]+);base64,(.+)$/i.exec(imageDataUrl.trim());
    if (!imageMatch) throw new Error("Imagem inválida para processamento por IA.");
    parts.push({
      inlineData: {
        mimeType: imageMatch[1],
        data: imageMatch[2],
      },
    });
  }

  const result = await model.generateContent({
    contents: [{ role: "user", parts }],
    generationConfig: {
      maxOutputTokens: 600,
      temperature: 0.2,
    },
  });

  return result.response.text().trim();
}

async function gerarRascunhoOrcamentoComOpenAI(prompt: string, imageDataUrl?: string | null) {
  const content: Array<
    | { type: "text"; text: string }
    | { type: "image_url"; image_url: { url: string } }
  > = [{ type: "text", text: prompt }];

  if (imageDataUrl) {
    content.push({
      type: "image_url",
      image_url: { url: imageDataUrl },
    });
  }

  const completion = await getOpenAIClient().chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content }],
    max_tokens: 600,
  });

  return (completion.choices[0]?.message?.content ?? "").trim();
}

export async function gerarRascunhoOrcamento(input: string | IAQuoteInput, todayIsoDate?: string): Promise<IAQuoteDraft> {
  const hoje = (todayIsoDate ?? new Date().toISOString().slice(0, 10)).trim();
  const instruction = typeof input === "string" ? input : String(input?.instruction ?? "").trim();
  const imageDataUrl = typeof input === "string" ? null : (input?.imageDataUrl?.trim() || null);
  const prompt = buildQuotePrompt(instruction, hoje);

  const raw =
    getProvider() === "openai"
      ? await gerarRascunhoOrcamentoComOpenAI(prompt, imageDataUrl)
      : await gerarRascunhoOrcamentoComGemini(prompt, imageDataUrl);

  const json = extractJsonObject(raw);
  const parsed = JSON.parse(json) as Partial<IAQuoteDraft>;
  const items = Array.isArray(parsed.items) ? parsed.items : [];

  const clientQuery = typeof parsed.client_query === "string" ? parsed.client_query.trim() : "";
  const clientWhatsapp = typeof parsed.client_whatsapp === "string" ? parsed.client_whatsapp.trim() : null;
  const title = typeof parsed.title === "string" ? parsed.title.trim() : null;
  const notes = typeof parsed.notes === "string" ? parsed.notes.trim() : null;
  const expiresAt = typeof parsed.expires_at === "string" ? parsed.expires_at.trim() : null;
  const deliveryDate = typeof parsed.delivery_date === "string" ? parsed.delivery_date.trim() : null;
  const status = normalizeQuoteStatus(parsed.status);

  return {
    client_query: clientQuery,
    client_whatsapp: clientWhatsapp,
    status,
    title: title || null,
    notes: notes || null,
    expires_at: expiresAt || null,
    delivery_date: deliveryDate || null,
    items: items
      .map((it) => ({
        title: typeof it?.title === "string" ? it.title.trim() : "",
        description: typeof it?.description === "string" ? it.description.trim() : null,
        unit_type: typeof it?.unit_type === "string" ? it.unit_type.trim() : null,
        width_m: typeof it?.width_m === "number" ? it.width_m : null,
        height_m: typeof it?.height_m === "number" ? it.height_m : null,
        length_m: typeof it?.length_m === "number" ? it.length_m : null,
        quantity: typeof it?.quantity === "number" ? it.quantity : null,
        unit_price: typeof it?.unit_price === "number" ? it.unit_price : null,
        unit_cost: typeof it?.unit_cost === "number" ? it.unit_cost : null,
      }))
      .filter((it) => it.title),
  };
}

export async function gerarDescricaoProduto(
  nome: string,
  categoria: string,
  caracteristicas: string
) {
  const prompt = buildPrompt(nome, categoria, caracteristicas);
  return getProvider() === "openai"
    ? await gerarDescricaoComOpenAI(prompt)
    : await gerarDescricaoComGemini(prompt);
}
