import { getSupabaseClient } from "@/lib/supabase";
import type { DocumentoDoBanner } from "./documento";

/*
 * As artes guardadas do editor (migration 222, artes_do_editor): a galeria
 * de "artes em andamento". O documento vai inteiro (o mesmo que o editor
 * mexe); quem confere peça por peça é o servidor, na hora de gerar a imagem.
 */

export type ResumoDaArte = { id: string; nome: string; largura: number; altura: number; formato: string | null; documento: DocumentoDoBanner; updated_at: string; created_at: string; quote_id?: string | null; quote_item_id?: string | null };

/* A arte ligada a um item do orçamento (migration 231): o "Criar no KtaloguDesign" do item. */
export type VinculoComOrcamento = { orcamento: string; item: string | null };

const COLUNAS = "id,nome,largura,altura,formato,documento,updated_at,created_at";
const COLUNAS_COM_ORCAMENTO = `${COLUNAS},quote_id,quote_item_id`;

/* As colunas da ligação com o orçamento ainda não existem (migration 231 não aplicada): segue sem elas. */
function faltaALigacao(erro: { code?: string; message?: string } | null) {
  return Boolean(erro && (erro.code === "42703" || erro.code === "PGRST204" || /quote_(item_)?id/.test(erro.message || "")));
}

/* A tabela ainda não existe no banco (migration não aplicada): a galeria avisa em vez de quebrar. */
function faltaATabela(erro: { code?: string; message?: string } | null) {
  return Boolean(erro && (erro.code === "42P01" || erro.code === "PGRST205" || /artes_do_editor/.test(erro.message || "")));
}

export class GaleriaIndisponivel extends Error {}

export async function listarArtes(dono: string, limite = 60): Promise<ResumoDaArte[]> {
  const { data, error } = await getSupabaseClient().from("artes_do_editor").select(COLUNAS).eq("user_id", dono).order("updated_at", { ascending: false }).limit(limite);
  if (faltaATabela(error)) throw new GaleriaIndisponivel("A galeria de artes ainda não está ligada.");
  if (error) throw new Error("Não deu para abrir as suas artes.");
  return (data || []) as ResumoDaArte[];
}

/* O design na galeria: sem o documento (a miniatura é uma foto; o documento vem só quando abre). */
export type ArteNaGaleria = Omit<ResumoDaArte, "documento">;

export async function listarArtesDaGaleria(dono: string, limite = 120): Promise<ArteNaGaleria[]> {
  const { data, error } = await getSupabaseClient().from("artes_do_editor").select("id,nome,largura,altura,formato,updated_at,created_at").eq("user_id", dono).order("updated_at", { ascending: false }).limit(limite);
  if (faltaATabela(error)) throw new GaleriaIndisponivel("A galeria de artes ainda não está ligada.");
  if (error) throw new Error("Não deu para abrir as suas artes.");
  return (data || []) as ArteNaGaleria[];
}

export async function abrirArte(id: string): Promise<ResumoDaArte | null> {
  let { data, error } = await getSupabaseClient().from("artes_do_editor").select(COLUNAS_COM_ORCAMENTO).eq("id", id).maybeSingle();
  if (faltaALigacao(error)) ({ data, error } = await getSupabaseClient().from("artes_do_editor").select(COLUNAS).eq("id", id).maybeSingle());
  if (faltaATabela(error)) throw new GaleriaIndisponivel("A galeria de artes ainda não está ligada.");
  if (error) throw new Error("Não deu para abrir essa arte.");
  return (data as ResumoDaArte | null) ?? null;
}

export async function criarArte(dono: string, arte: { nome: string; largura: number; altura: number; formato?: string | null; documento: DocumentoDoBanner; vinculo?: VinculoComOrcamento | null }): Promise<string> {
  const linha = { user_id: dono, nome: arte.nome.slice(0, 120) || "Arte sem nome", largura: Math.round(arte.largura), altura: Math.round(arte.altura), formato: arte.formato ?? null, documento: arte.documento };
  const ligacao = arte.vinculo ? { quote_id: arte.vinculo.orcamento, quote_item_id: arte.vinculo.item } : null;
  let { data, error } = await getSupabaseClient()
    .from("artes_do_editor")
    .insert(ligacao ? { ...linha, ...ligacao } : linha)
    .select("id")
    .single();
  if (ligacao && faltaALigacao(error)) ({ data, error } = await getSupabaseClient().from("artes_do_editor").insert(linha).select("id").single());
  if (faltaATabela(error)) throw new GaleriaIndisponivel("A galeria de artes ainda não está ligada.");
  if (error || !data) throw new Error(error?.message?.includes("grande demais") ? error.message : "Não deu para guardar a arte.");
  return String((data as { id: string }).id);
}

export async function salvarArte(id: string, campos: { nome?: string; largura?: number; altura?: number; formato?: string | null; documento?: DocumentoDoBanner }) {
  const carga: Record<string, unknown> = {};
  if (campos.nome !== undefined) carga.nome = campos.nome.slice(0, 120) || "Arte sem nome";
  if (campos.largura !== undefined) carga.largura = Math.round(campos.largura);
  if (campos.altura !== undefined) carga.altura = Math.round(campos.altura);
  if (campos.formato !== undefined) carga.formato = campos.formato;
  if (campos.documento !== undefined) carga.documento = campos.documento;
  const { error } = await getSupabaseClient().from("artes_do_editor").update(carga).eq("id", id);
  if (faltaATabela(error)) throw new GaleriaIndisponivel("A galeria de artes ainda não está ligada.");
  if (error) throw new Error(error.message?.includes("grande demais") ? error.message : "Não deu para guardar a arte.");
}

export async function apagarArte(id: string) {
  const { error } = await getSupabaseClient().from("artes_do_editor").delete().eq("id", id);
  if (error) throw new Error("Não deu para apagar a arte.");
}

export async function duplicarArte(dono: string, arte: ResumoDaArte) {
  return criarArte(dono, { nome: `${arte.nome} (cópia)`.slice(0, 120), largura: arte.largura, altura: arte.altura, formato: arte.formato, documento: arte.documento });
}

/** As artes ligadas aos itens de um orçamento (as mais novas primeiro); sem a migration 231, nenhuma. */
export async function artesDoOrcamento(orcamento: string): Promise<Array<{ id: string; nome: string; quote_item_id: string | null; updated_at: string }>> {
  const { data, error } = await getSupabaseClient().from("artes_do_editor").select("id,nome,quote_item_id,updated_at").eq("quote_id", orcamento).order("updated_at", { ascending: false }).limit(60);
  if (error) return [];
  return (data || []) as Array<{ id: string; nome: string; quote_item_id: string | null; updated_at: string }>;
}

/** As imagens enviadas pela pessoa que aparecem nas artes guardadas (para reaproveitar). */
export function imagensEnviadas(artes: ResumoDaArte[]) {
  const vistas = new Set<string>();
  for (const arte of artes) {
    for (const p of arte.documento?.pecas || []) {
      if (p.tipo === "imagem" && p.papel === "foto" && /\/editor\/imagens\//.test(p.src)) vistas.add(p.src);
    }
  }
  return [...vistas];
}

/** Baixar a arte (PNG, JPG ou PDF) pelo servidor; volta o arquivo para salvar. */
export async function baixarArte(pedido: { documento: DocumentoDoBanner; largura: number; altura: number; nome: string; formato: "png" | "jpg" | "pdf"; escala: number; qualidade: number; transparente: boolean; grafica?: boolean; espelhar?: boolean }, soArquivo = false) {
  const resposta = await fetch("/api/artes/exportar", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(pedido) });
  if (!resposta.ok) {
    const corpo = (await resposta.json().catch(() => ({}))) as { error?: string };
    throw new Error(corpo.error || "Não deu para gerar a arte agora. Tente de novo em instantes.");
  }
  const arquivo = await resposta.blob();
  const escala = Number(resposta.headers.get("X-Escala")) || pedido.escala;
  const nome = /filename="([^"]+)"/.exec(resposta.headers.get("Content-Disposition") || "")?.[1] || `arte.${pedido.formato}`;
  /* Para o .zip: devolve o arquivo em vez de baixar. */
  if (soArquivo) return { escala, tamanho: arquivo.size, arquivo, nome };
  const endereco = URL.createObjectURL(arquivo);
  const link = document.createElement("a");
  link.href = endereco;
  link.download = nome;
  document.body.appendChild(link);
  link.click();
  link.remove();
  window.setTimeout(() => URL.revokeObjectURL(endereco), 30_000);
  return { escala, tamanho: arquivo.size, arquivo, nome };
}
