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

import {
  getBankAccountDependencies,
  getBankAccountSnapshot,
  logBankAccountAuditEvent,
} from "@/lib/bank-account-admin";
import { getLiquidationAccountDisplayName, isCashAccountType } from "@/lib/liquidation-accounts";

/* Transferência entre contas da empresa. Saiu de
   app/api/bank-accounts/transfer/route.ts para que a tela e o assistente
   gravem do mesmo jeito: duas linhas no fluxo de caixa com a mesma marca e o
   registro de auditoria nas duas contas. Quem chama confere que a pessoa é
   dona ou administradora. */

export type CorpoDaTransferencia = {
  source_bank_account_id?: unknown;
  destination_bank_account_id?: unknown;
  amount?: unknown;
  date?: unknown;
  reason?: unknown;
} | null;

export type ResultadoDaTransferencia =
  | { ok: true; corpo: Record<string, unknown> }
  | { ok: false; status: number; corpo: Record<string, unknown> };

function falhou(status: number, corpo: Record<string, unknown>) {
  return { ok: false as const, status, corpo };
}

function normalizeIsoDate(value: unknown) {
  if (typeof value !== "string") return null;
  const trimmed = value.trim();
  if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return null;
  return trimmed;
}

export async function transferirEntreContas(params: {
  supabase: SupabaseClient;
  companyId: string;
  tenantIds: string[];
  userId: string;
  body: CorpoDaTransferencia;
}): Promise<ResultadoDaTransferencia> {
  const { supabase, companyId, tenantIds, userId, body } = params;
  const sourceBankAccountId =
    typeof body?.source_bank_account_id === "string" ? body.source_bank_account_id.trim() : "";
  const destinationBankAccountId =
    typeof body?.destination_bank_account_id === "string" ? body.destination_bank_account_id.trim() : "";
  const amount = typeof body?.amount === "number" ? body.amount : Number(body?.amount);
  const date = normalizeIsoDate(body?.date) || new Date().toISOString().slice(0, 10);
  const reason = typeof body?.reason === "string" ? body.reason.trim() : "";

  if (!sourceBankAccountId) {
    return falhou(400, { error: "Conta de origem é obrigatória." });
  }
  if (!destinationBankAccountId) {
    return falhou(400, { error: "Conta de destino é obrigatória." });
  }
  if (sourceBankAccountId === destinationBankAccountId) {
    return falhou(400, { error: "Origem e destino devem ser contas diferentes." });
  }
  if (!Number.isFinite(amount) || amount <= 0) {
    return falhou(400, { error: "Valor da transferência inválido." });
  }
  if (!reason) {
    return falhou(400, { error: "Informe o motivo da transferência." });
  }

  const [sourceBefore, destinationBefore] = await Promise.all([
    getBankAccountSnapshot(supabase, companyId, sourceBankAccountId),
    getBankAccountSnapshot(supabase, companyId, destinationBankAccountId),
  ]);

  if (!sourceBefore) {
    return falhou(404, { error: "Conta de origem não encontrada." });
  }
  if (!destinationBefore) {
    return falhou(404, { error: "Conta de destino não encontrada." });
  }
  if (sourceBefore.active === false) {
    return falhou(400, { error: "A conta de origem está bloqueada." });
  }
  if (destinationBefore.active === false) {
    return falhou(400, { error: "A conta de destino está bloqueada." });
  }
  /* Qualquer conta para qualquer conta (antes só caixa físico -> banco, e a
     empresa precisava virar a conta corrente em caixa para transferir).
     Só o caixa físico não fica negativo: dinheiro na gaveta não tem cheque especial. */
  const origemEhCaixa = isCashAccountType(sourceBefore.type);
  const destinoEhCaixa = isCashAccountType(destinationBefore.type);
  if (origemEhCaixa && sourceBefore.current_balance + 0.0001 < amount) {
    return falhou(409, {
      error: "Saldo insuficiente no caixa físico para realizar a transferência.",
      details: {
        available_balance: sourceBefore.current_balance,
        requested_amount: amount,
      },
    });
  }

  const dependencies = await getBankAccountDependencies(
    companyId,
    sourceBankAccountId,
    tenantIds
  );
  if (dependencies.open_pdv_cash_sessions > 0) {
    return falhou(409, { error: "Não é possível transferir saldo com um caixa PDV aberto nesta conta de origem." });
  }

  const transferId = crypto.randomUUID();
  const sourceLabel = getLiquidationAccountDisplayName(sourceBefore);
  const destinationLabel = getLiquidationAccountDisplayName(destinationBefore);
  const marca = origemEhCaixa ? "CAIXA" : "CONTA";
  const sourceDescription = `[TRANSFERENCIA:${marca}:SAIDA:${transferId}] Transferência para ${destinationLabel} • ${reason}`;
  const destinationDescription = `[TRANSFERENCIA:${marca}:ENTRADA:${transferId}] Transferência recebida de ${sourceLabel} • ${reason}`;

  const { error: insertError } = await supabase.from("cash_flow").insert([
    {
      company_id: companyId,
      bank_account_id: sourceBankAccountId,
      type: "OUT",
      origin: "AJUSTE",
      reference_id: null,
      description: sourceDescription,
      amount,
      date,
    },
    {
      company_id: companyId,
      bank_account_id: destinationBankAccountId,
      type: "IN",
      origin: "AJUSTE",
      reference_id: null,
      description: destinationDescription,
      amount,
      date,
    },
  ]);

  if (insertError) {
    return falhou(500, { error: "Falha ao registrar a transferência auditável.", message: insertError.message });
  }

  const [sourceAfter, destinationAfter] = await Promise.all([
    getBankAccountSnapshot(supabase, companyId, sourceBankAccountId),
    getBankAccountSnapshot(supabase, companyId, destinationBankAccountId),
  ]);

  const metadata = {
    transfer_id: transferId,
    transfer_type: `${origemEhCaixa ? "cash" : "bank"}_to_${destinoEhCaixa ? "cash" : "bank"}`,
    date,
    amount,
    reason,
    source: {
      bank_account_id: sourceBankAccountId,
      name: sourceLabel,
      before_balance: sourceBefore.current_balance,
      after_balance: sourceAfter?.current_balance ?? null,
    },
    destination: {
      bank_account_id: destinationBankAccountId,
      name: destinationLabel,
      before_balance: destinationBefore.current_balance,
      after_balance: destinationAfter?.current_balance ?? null,
    },
  };

  await Promise.all([
    logBankAccountAuditEvent({
      companyId: companyId,
      bankAccountId: sourceBankAccountId,
      userId: userId,
      eventType: "BALANCE_ADJUSTMENT",
      reason: `Transferência para ${destinationLabel}. ${reason}`,
      beforeState: sourceBefore,
      afterState: sourceAfter,
      metadata: {
        ...metadata,
        perspective: "source",
        cash_flow_type: "OUT",
      },
    }),
    logBankAccountAuditEvent({
      companyId: companyId,
      bankAccountId: destinationBankAccountId,
      userId: userId,
      eventType: "BALANCE_ADJUSTMENT",
      reason: `Transferência recebida de ${sourceLabel}. ${reason}`,
      beforeState: destinationBefore,
      afterState: destinationAfter,
      metadata: {
        ...metadata,
        perspective: "destination",
        cash_flow_type: "IN",
      },
    }),
  ]);

  return {
    ok: true as const,
    corpo: {
      ok: true,
      transfer: metadata,
      source_account: sourceAfter,
      destination_account: destinationAfter,
    },
  };
}
