import * as kv from "./kv_store.tsx";

export type ResultadoIntegridadeDocumento = {
  pode: boolean;
  motivo?: string;
};

type VerificarLancamentoDefinitivoParams = {
  empresaId?: string;
  documentoId?: string;
  numeroDocumento?: string;
  rotuloDocumento?: string;
};

export type LancamentoRascunhoRemovido = { key: string; value: any };

function normalizarTexto(valor?: unknown): string {
  return String(valor || "").trim().toLowerCase();
}

function lancamentoReferenciaDocumento(lancamento: any, documentoId: string, numeroDocumento: string): boolean {
  const lancamentoDocumentoId = normalizarTexto(lancamento?.documentoId);
  const lancamentoNumero = normalizarTexto(lancamento?.numeroDocumento);
  const documentoIds = Array.isArray(lancamento?.documentoIds) ? lancamento.documentoIds : [];

  if (documentoId && lancamentoDocumentoId === documentoId) return true;
  if (documentoId && documentoIds.some((id: unknown) => normalizarTexto(id) === documentoId)) return true;
  if (numeroDocumento && lancamentoNumero === numeroDocumento) return true;

  return false;
}

export async function verificarSemLancamentoContabilDefinitivo({
  empresaId,
  documentoId,
  numeroDocumento,
  rotuloDocumento = "Documento",
}: VerificarLancamentoDefinitivoParams): Promise<ResultadoIntegridadeDocumento> {
  const empresa = String(empresaId || "").trim();
  const docId = normalizarTexto(documentoId);
  const numero = normalizarTexto(numeroDocumento);

  if (!empresa || (!docId && !numero)) {
    return { pode: true };
  }

  const lancamentos = await kv.getByPrefix<any>(`lancamento_${empresa}_`);
  const lancamentoDefinitivo = lancamentos.find((lancamento: any) => {
    if (normalizarTexto(lancamento?.estado) !== "lancado") return false;
    return lancamentoReferenciaDocumento(lancamento, docId, numero);
  });

  if (lancamentoDefinitivo) {
    return {
      pode: false,
      motivo: `${rotuloDocumento} ja foi lancado definitivamente na contabilidade (${lancamentoDefinitivo.referencia || "lancamento contabil"}). Estorne ou reverta o lancamento antes de alterar o documento.`,
    };
  }

  return { pode: true };
}

export async function assegurarSemLancamentoContabilDefinitivo(params: VerificarLancamentoDefinitivoParams): Promise<void> {
  const resultado = await verificarSemLancamentoContabilDefinitivo(params);
  if (!resultado.pode) {
    throw new Error(resultado.motivo || "Documento bloqueado por lancamento contabil definitivo.");
  }
}

export async function removerLancamentosContabeisRascunhoDoDocumento({
  empresaId,
  documentoId,
  numeroDocumento,
}: VerificarLancamentoDefinitivoParams): Promise<LancamentoRascunhoRemovido[]> {
  const empresa = String(empresaId || "").trim();
  const docId = normalizarTexto(documentoId);
  const numero = normalizarTexto(numeroDocumento);
  if (!empresa || (!docId && !numero)) return [];

  const lancamentos = await kv.getByPrefixWithKeys<any>(`lancamento_${empresa}_`);
  const rascunhos = lancamentos.filter(({ value }) =>
    normalizarTexto(value?.estado) === "rascunho" &&
    lancamentoReferenciaDocumento(value, docId, numero)
  );

  if (rascunhos.length > 0) {
    await kv.mdel(rascunhos.map(({ key }) => key));
  }

  return rascunhos;
}

export async function restaurarLancamentosContabeisRascunho(
  lancamentos: LancamentoRascunhoRemovido[],
): Promise<void> {
  if (lancamentos.length === 0) return;
  await kv.mset(
    lancamentos.map(({ key }) => key),
    lancamentos.map(({ value }) => value),
  );
}
