import {
  ambienteFiscal,
  mercadoPagoEmTeste,
  tokenDoMercadoPagoDaKtalogu,
  type AmbienteFiscal,
} from "@/lib/fiscal/ambiente";
import {
  criarPreferenciaDoPacote,
  obterPagamento,
  pagamentoParaOBanco,
  pagamentoQueManda,
  pagamentosDaCompra,
} from "@/lib/fiscal/mercado-pago-ktalogu";

import { aplicarAvisoDaLive } from "@/lib/live/servidor/compras";

import { competenciaAtual, regrasDaPlataforma, saldoDoMes, type Admin } from "./base";
import { ErroFiscal } from "./notas";

export type PacoteDeNotas = {
  id: string;
  nome: string;
  descricao: string | null;
  quantidade: number;
  preco: number;
  ativo: boolean;
  destaque: boolean;
  ordem: number;
};

export type CompraDeNotas = {
  id: string;
  empresa_id: string;
  ambiente: AmbienteFiscal;
  pacote_id: string | null;
  pacote_nome: string;
  quantidade: number;
  preco: number;
  competencia: string;
  status: "pendente" | "aprovada" | "recusada" | "cancelada" | "reembolsada" | "contestada";
  mp_preferencia_id: string | null;
  mp_pagamento_id: string | null;
  mp_status: string | null;
  mp_status_detalhe: string | null;
  forma_pagamento: string | null;
  checkout_url: string | null;
  criada_por: string | null;
  aprovada_em: string | null;
  created_at: string;
  updated_at: string;
};

export async function pacotesAVenda(admin: Admin): Promise<PacoteDeNotas[]> {
  const { data, error } = await admin
    .from("fiscal_pacotes")
    .select("id,nome,descricao,quantidade,preco,ativo,destaque,ordem")
    .eq("ativo", true)
    .order("ordem", { ascending: true })
    .order("quantidade", { ascending: true });
  if (error) throw new ErroFiscal(`Falha ao ler os pacotes: ${error.message}`, 500);
  return ((data ?? []) as PacoteDeNotas[]).map((p) => ({ ...p, preco: Number(p.preco), quantidade: Number(p.quantidade) }));
}

/**
 * Quem contestou um pagamento no cartão não compra de novo: as notas daquele
 * pacote já saíram e o dinheiro voltou. O sistema não tem como cobrar de
 * volta, então o que resta é fechar a porta até o suporte olhar.
 */
export async function bloqueioDeCompra(admin: Admin, empresaId: string, ambiente: AmbienteFiscal): Promise<string | null> {
  const { data } = await admin
    .from("fiscal_compras")
    .select("id")
    .eq("empresa_id", empresaId)
    .eq("ambiente", ambiente)
    .eq("status", "contestada")
    .limit(1);
  return data?.length
    ? "A compra de pacotes está bloqueada para esta empresa por causa de uma contestação de pagamento. Fale com o suporte do Ktalogu."
    : null;
}

export async function painelDeCreditos(admin: Admin, empresaId: string, ambiente: AmbienteFiscal) {
  const competencia = await competenciaAtual(admin);
  const [saldo, pacotes, regras, bloqueioDeCompraMsg, extratoR, comprasR] = await Promise.all([
    saldoDoMes(admin, empresaId, ambiente, competencia),
    pacotesAVenda(admin),
    regrasDaPlataforma(admin),
    bloqueioDeCompra(admin, empresaId, ambiente),
    admin
      .from("fiscal_creditos")
      .select("id,competencia,tipo,quantidade,descricao,nota_id,compra_id,created_at")
      .eq("empresa_id", empresaId)
      .eq("ambiente", ambiente)
      .order("created_at", { ascending: false })
      .limit(60),
    admin
      .from("fiscal_compras")
      .select("id,pacote_nome,quantidade,preco,competencia,status,mp_status,mp_status_detalhe,forma_pagamento,checkout_url,aprovada_em,created_at")
      .eq("empresa_id", empresaId)
      .eq("ambiente", ambiente)
      /* Compra cujo pagamento nem chegou a abrir não é compra: fica no banco
         para diagnóstico, mas não aparece como "cancelada" para a empresa. */
      .or("mp_status_detalhe.is.null,mp_status_detalhe.neq.preferencia_falhou")
      .order("created_at", { ascending: false })
      .limit(24),
  ]);
  return {
    competencia,
    saldo,
    pacotes,
    vendasAbertas: regras.vendas_abertas && Boolean(tokenDoMercadoPagoDaKtalogu()),
    bloqueioDeCompra: bloqueioDeCompraMsg,
    avisoSaldoBaixo: regras.aviso_saldo_baixo,
    extrato: extratoR.data ?? [],
    compras: comprasR.data ?? [],
  };
}

export async function criarCompra(
  admin: Admin,
  input: {
    empresaId: string;
    ambiente: AmbienteFiscal;
    pacoteId: string;
    usuarioId: string;
    email: string | null;
    nome: string | null;
    origem: string;
  }
) {
  const token = tokenDoMercadoPagoDaKtalogu();
  if (!token) throw new ErroFiscal("A venda de pacotes está fechada no momento.", 503);
  if (input.ambiente === "producao" && mercadoPagoEmTeste(token)) {
    throw new ErroFiscal("A venda de pacotes está em manutenção.", 503);
  }
  const regras = await regrasDaPlataforma(admin);
  if (!regras.vendas_abertas) throw new ErroFiscal("A venda de pacotes está pausada no momento.", 503);
  const bloqueio = await bloqueioDeCompra(admin, input.empresaId, input.ambiente);
  if (bloqueio) throw new ErroFiscal(bloqueio, 403);

  const { data: pacote } = await admin
    .from("fiscal_pacotes")
    .select("id,nome,quantidade,preco,ativo")
    .eq("id", input.pacoteId)
    .maybeSingle();
  if (!pacote || !pacote.ativo) throw new ErroFiscal("Este pacote não está mais à venda.", 404);

  /* Clique repetido: reaproveita o checkout aberto há pouco do mesmo pacote. */
  const meiaHora = new Date(Date.now() - 30 * 60 * 1000).toISOString();
  const { data: aberta } = await admin
    .from("fiscal_compras")
    .select("id,checkout_url,preco")
    .eq("empresa_id", input.empresaId)
    .eq("ambiente", input.ambiente)
    .eq("pacote_id", pacote.id)
    .eq("status", "pendente")
    .gte("created_at", meiaHora)
    .not("checkout_url", "is", null)
    .order("created_at", { ascending: false })
    .limit(1)
    .maybeSingle();
  if (aberta?.checkout_url && Number(aberta.preco) === Number(pacote.preco)) {
    return { compraId: String(aberta.id), checkoutUrl: String(aberta.checkout_url) };
  }

  const competencia = await competenciaAtual(admin);
  const { data: compra, error } = await admin
    .from("fiscal_compras")
    .insert({
      empresa_id: input.empresaId,
      ambiente: input.ambiente,
      pacote_id: pacote.id,
      pacote_nome: pacote.nome,
      quantidade: pacote.quantidade,
      preco: pacote.preco,
      competencia,
      criada_por: input.usuarioId,
    })
    .select("id")
    .single();
  if (error || !compra) throw new ErroFiscal(`Falha ao registrar a compra: ${error?.message ?? ""}`, 500);

  const origem = input.origem.replace(/\/+$/, "");
  const urlDeVolta = `${origem}/dashboard/assinatura?aba=notas&compra=${compra.id}`;
  const urlDoAviso = origem.startsWith("https://") ? `${origem}/api/webhooks/mercado-pago-ktalogu?source_news=webhooks` : null;

  try {
    const preferencia = await criarPreferenciaDoPacote({
      token,
      compraId: String(compra.id),
      pacote: { nome: String(pacote.nome), quantidade: Number(pacote.quantidade), preco: Number(pacote.preco) },
      comprador: { email: input.email, nome: input.nome },
      urlDeVolta,
      urlDoAviso,
    });
    const checkoutUrl =
      (mercadoPagoEmTeste(token) ? preferencia.sandbox_init_point || preferencia.init_point : preferencia.init_point) || null;
    if (!checkoutUrl) throw new Error("O Mercado Pago não devolveu o link de pagamento.");
    await admin
      .from("fiscal_compras")
      .update({ mp_preferencia_id: preferencia.id, checkout_url: checkoutUrl, updated_at: new Date().toISOString() })
      .eq("id", compra.id);
    return { compraId: String(compra.id), checkoutUrl };
  } catch (erro) {
    await admin
      .from("fiscal_compras")
      .update({ status: "cancelada", mp_status_detalhe: "preferencia_falhou", updated_at: new Date().toISOString() })
      .eq("id", compra.id);
    throw new ErroFiscal(erro instanceof Error ? erro.message : "Não foi possível abrir o pagamento.", 503);
  }
}

export async function conferirCompra(admin: Admin, input: { compraId: string; empresaId?: string | null }) {
  let consulta = admin.from("fiscal_compras").select("*").eq("id", input.compraId);
  if (input.empresaId) consulta = consulta.eq("empresa_id", input.empresaId);
  const { data: compra } = await consulta.maybeSingle();
  if (!compra) throw new ErroFiscal("Compra não encontrada.", 404);
  const atual = compra as CompraDeNotas;
  if (atual.ambiente !== ambienteFiscal()) return atual;

  const token = tokenDoMercadoPagoDaKtalogu();
  if (!token) return atual;

  const pagamentos = await pagamentosDaCompra(token, atual.id);
  const manda = pagamentoQueManda(pagamentos);
  if (!manda) {
    const horas = (Date.now() - new Date(atual.created_at).getTime()) / 3600000;
    if (atual.status === "pendente" && horas > 48) {
      await admin
        .from("fiscal_compras")
        .update({ status: "cancelada", mp_status_detalhe: "expirada", updated_at: new Date().toISOString() })
        .eq("id", atual.id)
        .eq("status", "pendente");
    }
    const { data } = await admin.from("fiscal_compras").select("*").eq("id", atual.id).single();
    return data as CompraDeNotas;
  }
  const { error } = await admin.rpc("fiscal_aplicar_pagamento_compra", { p_compra: atual.id, p_pagamento: pagamentoParaOBanco(manda) });
  if (error) throw new ErroFiscal(`Falha ao aplicar o pagamento: ${error.message}`, 500);
  const { data } = await admin.from("fiscal_compras").select("*").eq("id", atual.id).single();
  return data as CompraDeNotas;
}

/** Aviso do Mercado Pago: lê o pagamento de verdade antes de acreditar. */
export async function aplicarAvisoDePagamento(admin: Admin, pagamentoId: string) {
  const token = tokenDoMercadoPagoDaKtalogu();
  if (!token) return { resultado: "sem_token" as const };
  const pagamento = await obterPagamento(token, pagamentoId);
  const compraId = String(pagamento.external_reference || "");
  if (!/^[0-9a-f-]{36}$/i.test(compraId)) return { resultado: "nao_e_pacote" as const };
  const { data: compra } = await admin.from("fiscal_compras").select("id,ambiente").eq("id", compraId).maybeSingle();
  /* O mesmo Mercado Pago vende o KtaloguLive: o aviso que não é de notas pode ser de lá. */
  if (!compra) return aplicarAvisoDaLive(admin, compraId, pagamento);
  if (compra.ambiente !== ambienteFiscal()) return { resultado: "outro_ambiente" as const };
  /* Entre vários pagamentos da compra, vale o que manda — não o deste aviso. */
  const todos = await pagamentosDaCompra(token, compraId).catch(() => [pagamento]);
  const manda = pagamentoQueManda(todos.length ? todos : [pagamento]) ?? pagamento;
  const { data, error } = await admin.rpc("fiscal_aplicar_pagamento_compra", { p_compra: compraId, p_pagamento: pagamentoParaOBanco(manda) });
  if (error) throw new Error(error.message);
  return { resultado: "aplicado" as const, detalhe: data };
}
