/*
  O Mercado Pago visto do balcão.

  A loja virtual já fala com o provedor há tempo — a integração, as chaves e o
  formato da resposta moram em `apps/public/src/lib/mercado-pago.ts`. O PDV
  precisa de uma fatia disso: ler a configuração, escolher a credencial do
  ambiente certo, chamar a API e achar o QR na resposta. Os dois apps não
  compartilham pacote, então esta é a cópia do admin. Mexeu na forma da
  configuração lá, mexe aqui.
*/

import type { SupabaseClient } from "@supabase/supabase-js";

export type AmbienteMercadoPago = "sandbox" | "production";

/* A forma gravada em `integrations.settings`. Os nomes são os do JSON
   guardado, por isso ficam em inglês. */
export type ConfiguracaoMercadoPago = {
  environment: AmbienteMercadoPago;
  checkout_enabled: boolean;
  auto_create_order_on_approved_payment: boolean;
  bank_account_id: string | null;
  sandbox_public_key: string;
  sandbox_access_token: string;
  production_public_key: string;
  production_access_token: string;
  statement_descriptor: string;
};

export type IntegracaoMercadoPago = {
  id: string;
  user_id: string;
  provider: string;
  settings: Record<string, unknown> | null;
  active: boolean | null;
};

export type EstadoDoPagamento = "approved" | "rejected" | "cancelled" | "refunded" | "charged_back" | "pending";

function texto(valor: unknown) {
  return String(valor ?? "").trim();
}

function booleano(valor: unknown, padrao: boolean) {
  if (typeof valor === "boolean") return valor;
  if (typeof valor === "string") {
    const normalizado = valor.trim().toLowerCase();
    if (normalizado === "true") return true;
    if (normalizado === "false") return false;
  }
  return padrao;
}

function objeto(valor: unknown) {
  return valor && typeof valor === "object" && !Array.isArray(valor) ? (valor as Record<string, unknown>) : null;
}

export function lerConfiguracaoDoMercadoPago(bruto: unknown): ConfiguracaoMercadoPago {
  const dados = objeto(bruto) || {};
  return {
    environment: dados.environment === "production" ? "production" : "sandbox",
    checkout_enabled: booleano(dados.checkout_enabled, true),
    auto_create_order_on_approved_payment: booleano(dados.auto_create_order_on_approved_payment, true),
    bank_account_id: texto(dados.bank_account_id) || null,
    sandbox_public_key: texto(dados.sandbox_public_key),
    sandbox_access_token: texto(dados.sandbox_access_token),
    production_public_key: texto(dados.production_public_key),
    production_access_token: texto(dados.production_access_token),
    statement_descriptor: texto(dados.statement_descriptor).slice(0, 13),
  };
}

/* A credencial do ambiente escolhido — ou nada, se faltar chave. Metade de
   uma credencial não serve para nada. */
export function credenciaisAtivas(config: ConfiguracaoMercadoPago) {
  if (config.environment === "production") {
    if (!config.production_public_key || !config.production_access_token) return null;
    return {
      ambiente: "production" as const,
      publicKey: config.production_public_key,
      accessToken: config.production_access_token,
    };
  }
  if (!config.sandbox_public_key || !config.sandbox_access_token) return null;
  return {
    ambiente: "sandbox" as const,
    publicKey: config.sandbox_public_key,
    accessToken: config.sandbox_access_token,
  };
}

export function estadoDoPagamento(valor: unknown): EstadoDoPagamento {
  const estado = texto(valor).toLowerCase();
  if (estado === "approved") return "approved";
  if (estado === "rejected") return "rejected";
  if (estado === "cancelled" || estado === "canceled") return "cancelled";
  if (estado === "refunded") return "refunded";
  if (estado === "charged_back") return "charged_back";
  return "pending";
}

/* O Pix vem em `point_of_interaction.transaction_data`: o código copia e
   cola, a imagem em base64 e o link do provedor. */
export function dadosDoQr(resposta: Record<string, unknown> | null | undefined) {
  const dados = objeto(objeto(resposta?.point_of_interaction)?.transaction_data);
  return {
    qrCode: texto(dados?.qr_code) || null,
    qrCodeBase64: texto(dados?.qr_code_base64) || null,
    ticketUrl: texto(dados?.ticket_url) || null,
  };
}

export async function chamarMercadoPago<T>(
  caminho: string,
  accessToken: string,
  init?: RequestInit & { chaveDeIdempotencia?: string | null }
): Promise<T> {
  const headers = new Headers(init?.headers || {});
  headers.set("Authorization", `Bearer ${accessToken}`);
  headers.set("Content-Type", "application/json");
  if (init?.chaveDeIdempotencia) headers.set("X-Idempotency-Key", init.chaveDeIdempotencia);

  const resposta = await fetch(`https://api.mercadopago.com${caminho}`, { ...init, headers, cache: "no-store" });
  const corpo = (await resposta.json().catch(() => ({}))) as T & { message?: string; error?: string; cause?: unknown };

  if (!resposta.ok) {
    /* O provedor explica o motivo em `cause` quando recusa o pedido; sem isso
       a mensagem genérica não diz nada a quem está no balcão. */
    const causa = Array.isArray(corpo?.cause)
      ? (corpo.cause as Array<{ description?: unknown }>).map((item) => texto(item?.description)).filter(Boolean).join(" ")
      : "";
    const mensagem = causa || texto(corpo?.message) || texto(corpo?.error) || "Não foi possível falar com o Mercado Pago.";
    throw new Error(mensagem);
  }

  return corpo;
}

/* A integração é uma por dono de conta: `user_id` é o dono, não quem está
   logado no balcão. */
export async function integracaoDoMercadoPago(admin: SupabaseClient, ownerId: string) {
  const { data, error } = await admin
    .from("integrations")
    .select("id,user_id,provider,settings,active")
    .eq("provider", "mercado_pago")
    .eq("user_id", ownerId)
    .maybeSingle();

  if (error) throw new Error(error.message || "Não foi possível carregar a integração do Mercado Pago.");
  return (data as IntegracaoMercadoPago | null) ?? null;
}

/*
  A data de vencimento no formato que o provedor aceita: com o fuso escrito
  por extenso (`-03:00`), nunca `Z`. O Brasil não tem horário de verão desde
  2019, então o deslocamento é fixo.
*/
export function vencimentoParaOProvedor(instante: Date) {
  const emBrasilia = new Date(instante.getTime() - 3 * 60 * 60 * 1000);
  return emBrasilia.toISOString().replace("Z", "-03:00");
}
