import { ChromeAusente } from "@/lib/catalogo-pdf/servidor/imprimir";
import { resolveCompanyPublicProfileId } from "@/lib/company-context";

import { COMO_ENTREGAR_O_ARQUIVO, entregarArquivo } from "../arquivos";
import { contatosNovos, recusaDeContatos } from "../contatos";
import { DESCRICAO_DO_CAMPO_DE_IMAGEM, receberImagem } from "../imagens";
import { exigir, falha, recusar } from "./comum";
import { arquivoFinal, imagemDoBanner } from "./gerador-de-banner-imagem";
import { BannerDemorou, GeradorOcupado, guardarImagemComoEnvio, imprimirImagem } from "./gerador-de-banner";
import { FONTE_PADRAO_DO_TITULO, type ImagemDoBanner } from "./gerador-de-banner-modelos";
import {
  contrasteBaixo,
  FORMATOS_DA_IMAGEM,
  fundoValido,
  htmlDaImagemDoProduto,
  MODOS_DA_IMAGEM,
  type FormatoDaImagem,
  type ModoDaImagem,
} from "./imagem-do-produto-modelo";
import { chaveDaFonte } from "./loja-e-documentos-aparencia";
import type { Ferramenta, FerramentaDeLeitura } from "./tipos";

/*
 * gerar_imagem_do_produto: uma imagem limpa para a galeria do produto,
 * fotografada pelo mesmo Chrome do gerador de banners. Não mexe no produto:
 * devolve a prévia e um código "envio:..." para adicionar_fotos_ao_produto
 * (ou criar_produto) depois que a pessoa aprovar.
 *
 * A imagem que o próprio chat gera não chega ao servidor: ou a pessoa envia
 * pelo link de pedir_imagem, ou o assistente usa esta ferramenta.
 */

const gerarImagemDoProduto: FerramentaDeLeitura = {
  tipo: "leitura",
  nome: "gerar_imagem_do_produto",
  titulo: "Gerar imagem de produto",
  descricao:
    'Cria uma imagem limpa para a galeria de um produto: "foto em fundo" (a foto do produto centralizada num fundo liso, branco ou na cor escolhida, com sombra suave e o nome embaixo, se quiser) ou "cartão com nome" (sem foto: o nome do produto grande sobre a cor da loja, como imagem provisória). Não muda o produto: devolve um link de prévia e um código "envio:..." para usar em adicionar_fotos_ao_produto ou criar_produto depois que a pessoa aprovar. Use quando a pessoa pedir para criar a imagem do produto; a imagem que você mesmo gera no chat não chega ao sistema (peça para a pessoa enviá-la pelo link de pedir_imagem).',
  campos: {
    modo: { tipo: "opcao", descricao: 'O jeito da imagem. Padrão: "foto em fundo" quando há imagem, "cartão com nome" sem ela.', opcoes: MODOS_DA_IMAGEM },
    imagem: { tipo: "texto", max: 2000, descricao: `A foto do produto, para "foto em fundo". ${DESCRICAO_DO_CAMPO_DE_IMAGEM}` },
    titulo: { tipo: "texto", max: 80, descricao: 'O nome que aparece (obrigatório no "cartão com nome"; opcional na foto).' },
    subtitulo: { tipo: "texto", max: 120, descricao: "Uma linha de apoio abaixo do nome (opcional)." },
    fundo: { tipo: "texto", max: 9, descricao: 'Cor de fundo, como #FFFFFF. Padrão: branco na "foto em fundo" e a cor da loja no "cartão com nome".' },
    formato: { tipo: "opcao", descricao: "quadrado (1200 × 1200, o padrão) ou retrato (1200 × 1500).", opcoes: Object.keys(FORMATOS_DA_IMAGEM) },
    fonte: { tipo: "texto", max: 40, descricao: "A fonte do nome (lista de ver_aparencia_da_loja). Padrão: a fonte de títulos da loja." },
  },
  permissoes: ["products.catalog.write"],
  abertoAoMundo: true,
  async executar(ctx, args) {
    exigir(ctx, "products.catalog.write", "criar imagens de produto");
    const modo: ModoDaImagem = (args.modo as ModoDaImagem | undefined) ?? (args.imagem ? "foto em fundo" : "cartão com nome");
    const formato = (args.formato as FormatoDaImagem | undefined) ?? "quadrado";
    const titulo = String(args.titulo ?? "").replace(/\s+/g, " ").trim();
    const subtitulo = String(args.subtitulo ?? "").replace(/\s+/g, " ").trim();
    if (modo === "foto em fundo" && !args.imagem) recusar('"foto em fundo" precisa da imagem do produto (campo imagem).');
    if (modo === "cartão com nome" && !titulo) recusar('"cartão com nome" precisa do nome (campo titulo).');
    const contatos = contatosNovos(null, `${titulo}\n${subtitulo}`);
    if (contatos.length) recusar(recusaDeContatos(contatos, "na tela do produto"));
    if (args.fundo !== undefined && !/^#[0-9a-f]{6}$/i.test(String(args.fundo).trim())) recusar("A cor de fundo precisa ser um código como #FFFFFF.");

    const { data, error } = await ctx.supabase
      .from("profiles")
      .select("primary_color,catalog_font_heading")
      .eq("id", resolveCompanyPublicProfileId(ctx.empresa, ctx.user.id))
      .maybeSingle();
    if (error) falha("ler a aparência da loja", error);
    const perfil = (data ?? {}) as { primary_color?: string | null; catalog_font_heading?: string | null };
    let fonte = chaveDaFonte(perfil.catalog_font_heading) || FONTE_PADRAO_DO_TITULO;
    if (args.fonte !== undefined) {
      const pedida = chaveDaFonte(args.fonte);
      if (!pedida) recusar(`A fonte "${String(args.fonte)}" não está na lista. Veja as fontes em ver_aparencia_da_loja.`);
      fonte = pedida;
    }
    const fundo = fundoValido(args.fundo as string | undefined, modo === "foto em fundo" ? "#FFFFFF" : fundoValido(perfil.primary_color, "#6D28D9"));

    let imagem: ImagemDoBanner | null = null;
    let origem: string | null = null;
    const avisos: string[] = [];
    if (modo === "foto em fundo") {
      const recebida = await receberImagem(ctx, args.imagem, { minimo: 120 });
      origem = recebida.origem;
      imagem = await imagemDoBanner(recebida.conteudo, 1400);
      if (Math.min(recebida.largura, recebida.altura) < 500) avisos.push(`A foto é pequena (${recebida.largura} × ${recebida.altura}) e pode ficar um pouco borrada.`);
      if (imagem.tipo === "foto") avisos.push("A foto já tem um fundo próprio (não é recorte): ela entra inteira, como um quadro sobre o fundo.");
    }
    if (titulo && contrasteBaixo(fundo)) avisos.push("O texto tem pouco contraste com o fundo escolhido.");

    const { largura, altura } = FORMATOS_DA_IMAGEM[formato];
    let png: Buffer;
    try {
      png = await imprimirImagem(htmlDaImagemDoProduto({ modo, formato, fundo, imagem, titulo, subtitulo, fonte }), largura, altura);
    } catch (erro) {
      if (erro instanceof ChromeAusente) recusar("O gerador de imagens não está disponível neste servidor agora. Avise o suporte da Ktalogu.");
      if (erro instanceof BannerDemorou) recusar("A imagem demorou demais para ficar pronta. Tente de novo em instantes.");
      if (erro instanceof GeradorOcupado) recusar("O gerador de imagens está ocupado com outros pedidos. Tente de novo em um minuto.");
      console.error("[mcp] imagem do produto", erro instanceof Error ? erro.message : erro);
      recusar("Não foi possível gerar a imagem agora. Tente de novo em instantes.");
    }
    const final = await arquivoFinal(png, false);
    const codigo = await guardarImagemComoEnvio(ctx, final, { paraQue: "imagem do produto", nome: "produto", largura, altura });
    const previa = await entregarArquivo(ctx, { conteudo: final.conteudo, nome: `imagem-do-produto.${final.extensao}`, tipo: final.tipo });
    return {
      dados: {
        previa_da_imagem: previa.link,
        vale_ate: previa.vale_ate,
        codigo_para_usar: `envio:${codigo}`,
        modo,
        tamanho: `${largura} × ${altura} px`,
        fundo,
        ...(origem ? { foto: origem } : {}),
        ...(avisos.length ? { avisos } : {}),
        proximo_passo:
          "Mostre a prévia à pessoa (o link abre a imagem). Se ela aprovar, use codigo_para_usar no campo imagem de adicionar_fotos_ao_produto (ou nas fotos de criar_produto). Se pedir mudanças, gere de novo com os campos ajustados. O código vale 24 horas.",
        como_entregar: COMO_ENTREGAR_O_ARQUIVO,
      },
      resumo: `Gerou uma imagem de produto (${modo}${titulo ? `: "${titulo}"` : ""})`,
    };
  },
};

export const FERRAMENTAS_DE_IMAGEM_DO_PRODUTO: Ferramenta[] = [gerarImagemDoProduto];
