import * as kv from "./kv_store.tsx";
import * as artigos from "./artigos.tsx";
import * as movimentosStock from "./movimentos-stock.tsx";
import * as stockLotes from "./stock-lotes.tsx";
import * as stockArmazem from "./stock-armazem.tsx";
import { buscarArmazemPorId } from "./armazens.tsx";
import { validarDataEmissaoCronologica } from "./documento-cronologia.tsx";
import * as exerciciosEconomicos from "./exercicios-economicos.tsx";
import { reservarNumeroSequencial } from "./document-numbering.tsx";
import {
  verificarSemLancamentoContabilDefinitivo,
  removerLancamentosContabeisRascunhoDoDocumento,
} from "./integridade-documentos.tsx";
import { buscarRegimeFiscalEmpresa, REGIMES_SEM_IVA } from "./validacao-fiscal.tsx";

export type TipoDocumentoCompra =
  | 'Fatura'
  | 'Factura'
  | 'Fatura-Recibo'
  | 'Factura-Recibo'
  | 'VD'
  | 'Venda a Dinheiro'
  | 'Recibo'
  | 'Guia'
  | 'Guia de Remessa'
  | 'Entrada de Mercadoria'
  | 'Pedido de Compra'
  | 'Ordem de Compra'
  | 'Proforma'
  | 'Nota Credito'
  | 'Nota Debito'
  | string;

type EfeitoStockDocumentoCompra = 'entrada' | 'saida' | 'nenhum';

interface PerfilDocumentoCompra {
  tipoNormalizado: string;
  movimentaStock: boolean;
  efeitoStock: EfeitoStockDocumentoCompra;
  exigeArmazem: boolean;
  geraLancamentoContabil: boolean;
  geraContaPagar: boolean;
  liquidacaoImediata: boolean;
  permiteRecepcaoPosterior: boolean;
}

function normalizarTipoDocumentoCompra(tipoDocumento?: string): string {
  const texto = (tipoDocumento || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_+|_+$/g, '');

  const aliases: Record<string, string> = {
    ft: 'factura',
    fatura: 'factura',
    factura: 'factura',
    fr: 'factura_recibo',
    fatura_recibo: 'factura_recibo',
    factura_recibo: 'factura_recibo',
    vd: 'venda_dinheiro',
    venda_a_dinheiro: 'venda_dinheiro',
    venda_dinheiro: 'venda_dinheiro',
    recibo: 'recibo',
    guia: 'guia_remessa',
    guia_de_remessa: 'guia_remessa',
    guia_remessa: 'guia_remessa',
    entrada: 'entrada_mercadoria',
    entrada_de_mercadoria: 'entrada_mercadoria',
    entrada_mercadoria: 'entrada_mercadoria',
    pedido: 'pedido_compra',
    pedido_de_compra: 'pedido_compra',
    pedido_compra: 'pedido_compra',
    ordem: 'ordem_compra',
    ordem_de_compra: 'ordem_compra',
    ordem_compra: 'ordem_compra',
    proforma: 'proforma',
    factura_proforma: 'proforma',
    fatura_proforma: 'proforma',
    nota_credito: 'nota_credito',
    nota_de_credito: 'nota_credito',
    nota_debito: 'nota_debito',
    nota_de_debito: 'nota_debito',
  };

  return aliases[texto] || texto || 'factura';
}

export function obterPerfilDocumentoCompra(tipoDocumento?: string): PerfilDocumentoCompra {
  const tipoNormalizado = normalizarTipoDocumentoCompra(tipoDocumento);

  if (['pedido_compra', 'ordem_compra', 'proforma'].includes(tipoNormalizado)) {
    return {
      tipoNormalizado,
      movimentaStock: false,
      efeitoStock: 'nenhum',
      exigeArmazem: false,
      geraLancamentoContabil: false,
      geraContaPagar: false,
      liquidacaoImediata: false,
      permiteRecepcaoPosterior: false,
    };
  }

  if (['guia_remessa', 'entrada_mercadoria'].includes(tipoNormalizado)) {
    return {
      tipoNormalizado,
      movimentaStock: true,
      efeitoStock: 'entrada',
      exigeArmazem: true,
      geraLancamentoContabil: false,
      geraContaPagar: false,
      liquidacaoImediata: false,
      permiteRecepcaoPosterior: false,
    };
  }

  if (tipoNormalizado === 'nota_credito') {
    return {
      tipoNormalizado,
      movimentaStock: true,
      efeitoStock: 'saida',
      exigeArmazem: true,
      geraLancamentoContabil: true,
      geraContaPagar: false,
      liquidacaoImediata: false,
      permiteRecepcaoPosterior: false,
    };
  }

  const liquidacaoImediata = ['factura_recibo', 'venda_dinheiro', 'recibo'].includes(tipoNormalizado);

  return {
    tipoNormalizado,
    movimentaStock: true,
    efeitoStock: 'entrada',
    exigeArmazem: true,
    geraLancamentoContabil: true,
    geraContaPagar: !liquidacaoImediata,
    liquidacaoImediata,
    permiteRecepcaoPosterior: false,
  };
}

export interface Compra {
  id: string;
  empresaId: string;
  fornecedorId: string;
  numeroDocumento: string;
  numeroInterno?: string;
  tipoDocumento: TipoDocumentoCompra;
  dataEmissao: string;
  exercicioEconomicoId?: string;
  anoExercicio?: number;
  dataVencimento?: string;
  linhas: LinhaCompra[];
  subtotal: number;
  descontoGlobal: number;
  totalIVA: number;
  totalGeral: number;
  estado: 'rascunho' | 'emitido' | 'pago' | 'parcialmente_pago' | 'anulado' | 'vencido';
  observacoes?: string;
  armazemId?: string;
  recepcaoStatus?: 'nao_recepcionada' | 'parcial' | 'recepcionada';
  movimentaStock?: boolean;
  geraLancamentoContabil?: boolean;
  geraContaPagar?: boolean;
  liquidacaoImediata?: boolean;
  recepcionadoEm?: string;
  recepcionadoPor?: string;
  dataCriacao: string;
  dataAtualizacao?: string;
  criadoPor?: string;
}

export interface RecepcaoLinhaCompra {
  id: string;
  linhaId: string;
  quantidade: number;
  lote?: string;
  dataValidade?: string;
  dataFabricacao?: string;
  armazemId: string;
  recebidoEm: string;
  recebidoPor?: string;
}

export interface LinhaCompra {
  id: string;
  artigoId?: string;
  codigo: string;
  descricao: string;
  tipoArtigo?: artigos.TipoArtigo;
  quantidade: number;
  unidade: string;
  precoUnitario: number;
  precoVenda?: number;
  desconto: number;
  iva: number;
  ivaIncluso: boolean;
  subtotal: number;
  codigoBarras?: string;
  lote?: string;
  dataValidade?: string;
  dataFabricacao?: string;
  armazemId?: string;
  imagemUrl?: string;
  quantidadeRecebida?: number;
  recepcoes?: RecepcaoLinhaCompra[];
}

export interface DetalheLinhaCompraProcessamento {
  linhaId: string;
  tipo?: artigos.TipoArtigo;
  precoVenda?: number;
  codigoBarras?: string;
  dataValidade?: string;
  lote?: string;
  armazemId?: string;
  imagemUrl?: string;
}

export interface DocumentoCompraProcessamentoInput {
  empresaId: string;
  fornecedorId: string;
  fornecedorNome?: string;
  fornecedorCodigo?: string;
  fornecedorNuit?: string;
  numeroDocumento: string;
  tipoDocumento: Compra['tipoDocumento'];
  dataEmissao: string;
  dataVencimento?: string;
  linhas: LinhaCompra[];
  detalhesLinhas?: DetalheLinhaCompraProcessamento[];
  subtotal: number;
  descontoGlobal: number;
  totalIVA: number;
  totalGeral: number;
  observacoes?: string;
  armazemId?: string;
  criadoPor?: string;
}

export interface PagamentoCompra {
  id: string;
  empresaId: string;
  fornecedorId: string;
  compraId?: string;
  numeroDocumento: string;
  dataEmissao: string;
  valor: number;
  metodoPagamento: 'Dinheiro' | 'Transferencia' | 'Cheque' | 'TPA' | 'Multicaixa' | 'M-Pesa' | 'Outro';
  contaBancaria?: string;
  banco?: string;
  referencia?: string;
  observacoes?: string;
  origem?: 'manual' | 'documento_compra_imediato';
  automatico?: boolean;
  contabilizarSeparado?: boolean;
  dataCriacao: string;
  criadoPor?: string;
}

interface DocumentoCompraComLinhasParaReversao {
  empresaId: string;
  numeroDocumento: string;
  tipoDocumento?: string;
  armazemId?: string;
  recepcionadoEm?: string;
  recepcionadoPor?: string;
  dataCriacao?: string;
  linhas: LinhaCompra[];
}

function obterAnoCompra(compra: Pick<Compra, 'dataEmissao' | 'dataCriacao'>): number {
  const referencia = compra.dataEmissao || compra.dataCriacao || new Date().toISOString();
  const data = new Date(referencia);
  return Number.isNaN(data.getTime()) ? new Date().getFullYear() : data.getFullYear();
}

function extrairSequenciaNumeroInterno(numero?: string): { sequencia: number; ano: number } | null {
  if (!numero) return null;
  const match = numero.trim().match(/^(\d+)\/(\d{4})$/);
  if (!match) return null;

  const sequencia = Number(match[1]);
  const ano = Number(match[2]);
  if (!Number.isFinite(sequencia) || !Number.isFinite(ano)) return null;

  return { sequencia, ano };
}

function gerarNumeroInternoCompra(ano: number, sequencia: number): string {
  return `${sequencia}/${ano}`;
}

async function garantirNumerosInternosCompras(compras: Compra[]): Promise<Compra[]> {
  if (compras.length === 0) {
    return compras;
  }

  const maioresSequenciasPorAno = new Map<number, number>();

  for (const compra of compras) {
    const parsed = extrairSequenciaNumeroInterno(compra.numeroInterno);
    if (!parsed) continue;

    const atual = maioresSequenciasPorAno.get(parsed.ano) || 0;
    if (parsed.sequencia > atual) {
      maioresSequenciasPorAno.set(parsed.ano, parsed.sequencia);
    }
  }

  const faltantes = compras
    .filter((compra) => !extrairSequenciaNumeroInterno(compra.numeroInterno))
    .sort((a, b) => {
      const dataA = new Date(a.dataCriacao || a.dataEmissao || 0).getTime();
      const dataB = new Date(b.dataCriacao || b.dataEmissao || 0).getTime();
      return dataA - dataB;
    });

  for (const compra of faltantes) {
    const ano = obterAnoCompra(compra);
    const proximaSequencia = (maioresSequenciasPorAno.get(ano) || 0) + 1;
    compra.numeroInterno = gerarNumeroInternoCompra(ano, proximaSequencia);
    maioresSequenciasPorAno.set(ano, proximaSequencia);
    await kv.set(`compra:${compra.id}`, compra);
  }

  return compras;
}

async function gerarProximoNumeroInternoCompra(
  empresaId: string,
  comprasBase?: Compra[],
  anoExercicio?: number,
): Promise<string> {
  const comprasEmpresa = comprasBase || await listarCompras(empresaId);
  const anoAtual = anoExercicio || new Date().getFullYear();
  const reserva = await reservarNumeroSequencial<Compra>({
    empresaId,
    modulo: "compras-fornecedores",
    tipoDocumento: "compra_numero_interno",
    ano: anoAtual,
    documentosExistentes: comprasEmpresa,
    extrairSequencia: (compra, ano) => {
      const parsed = extrairSequenciaNumeroInterno(compra.numeroInterno);
      return parsed && parsed.ano === ano ? parsed.sequencia : null;
    },
    formatarNumero: (sequencia, ano) => gerarNumeroInternoCompra(ano, sequencia),
  });

  return reserva.numeroDocumento;

  let maiorSequencia = 0;

  for (const compra of comprasEmpresa) {
    const parsed = extrairSequenciaNumeroInterno(compra.numeroInterno);
    if (parsed && parsed.ano === anoAtual && parsed.sequencia > maiorSequencia) {
      maiorSequencia = parsed.sequencia;
    }
  }

  return gerarNumeroInternoCompra(anoAtual, maiorSequencia + 1);
}

function obterQuantidadeRecebidaLinha(linha: LinhaCompra): number {
  if (typeof linha.quantidadeRecebida === 'number') {
    return linha.quantidadeRecebida;
  }

  return (linha.recepcoes || []).reduce((sum, recepcao) => sum + recepcao.quantidade, 0);
}

function calcularRecepcaoStatus(compra: Compra): Compra['recepcaoStatus'] {
  const linhasComProduto = compra.linhas.filter((linha) =>
    !!linha.artigoId &&
    (linha.tipoArtigo || 'produto') === 'produto' &&
    linha.quantidade > 0
  );

  if (linhasComProduto.length === 0) {
    return 'nao_recepcionada';
  }

  const totalRecebido = linhasComProduto.reduce((sum, linha) => sum + obterQuantidadeRecebidaLinha(linha), 0);
  if (totalRecebido <= 0) {
    return 'nao_recepcionada';
  }

  const totalmenteRecepcionada = linhasComProduto.every((linha) => obterQuantidadeRecebidaLinha(linha) >= linha.quantidade);
  return totalmenteRecepcionada ? 'recepcionada' : 'parcial';
}

function documentoTipoCorrespondeCompra(movimentoTipo?: string, documentoTipo?: string): boolean {
  if (!documentoTipo) return true;

  const movimento = (movimentoTipo || '').trim().toLowerCase();
  const documento = documentoTipo.trim().toLowerCase();

  return movimento === documento || movimento === `compra ${documento}`;
}

function somarPagamentosCompra(pagamentos: PagamentoCompra[]): number {
  return pagamentos.reduce((sum, pagamento) => sum + Number(pagamento.valor || 0), 0);
}

async function listarPagamentosAssociadosCompra(compra: Pick<Compra, 'id' | 'empresaId'>): Promise<PagamentoCompra[]> {
  const pagamentosEmpresa = await listarPagamentosCompra(compra.empresaId);
  return pagamentosEmpresa.filter((pagamento) => pagamento.compraId === compra.id);
}

function calcularEstadoPagamentoCompra(compra: Compra, totalPago: number): Compra['estado'] {
  if (compra.estado === 'anulado') return 'anulado';

  const totalDocumento = Number(compra.totalGeral || 0);
  if (totalPago <= 0) return 'emitido';
  if (totalPago + 0.0001 >= totalDocumento) return 'pago';
  return 'parcialmente_pago';
}

function obterEstadoInicialDocumentoCompra(perfil: PerfilDocumentoCompra): Compra['estado'] {
  if (perfil.liquidacaoImediata) return 'pago';
  return 'emitido';
}

function pagamentoCompraAutomatico(pagamento: PagamentoCompra): boolean {
  return pagamento.origem === 'documento_compra_imediato' || pagamento.automatico === true;
}

async function removerPagamentoCompraInterno(pagamento: PagamentoCompra): Promise<void> {
  await kv.del(`pagamento_compra:${pagamento.id}`);

  const pagamentosEmpresa = await kv.get(`pagamentos_compra_empresa:${pagamento.empresaId}`) || [];
  await kv.set(
    `pagamentos_compra_empresa:${pagamento.empresaId}`,
    pagamentosEmpresa.filter((id: string) => id !== pagamento.id),
  );

  const pagamentosFornecedor = await kv.get(`pagamentos_compra_fornecedor:${pagamento.fornecedorId}`) || [];
  await kv.set(
    `pagamentos_compra_fornecedor:${pagamento.fornecedorId}`,
    pagamentosFornecedor.filter((id: string) => id !== pagamento.id),
  );
}

async function removerPagamentosAutomaticosCompra(compra: Pick<Compra, 'id' | 'empresaId'>): Promise<void> {
  const pagamentosAssociados = await listarPagamentosAssociadosCompra(compra);
  for (const pagamento of pagamentosAssociados) {
    if (pagamentoCompraAutomatico(pagamento)) {
      await removerPagamentoCompraInterno(pagamento);
    }
  }
}

async function sincronizarPagamentoImediatoCompra(compra: Compra, dados?: Partial<DocumentoCompraProcessamentoInput>): Promise<void> {
  const perfil = obterPerfilDocumentoCompra(compra.tipoDocumento);
  await removerPagamentosAutomaticosCompra(compra);

  if (!perfil.liquidacaoImediata || Number(compra.totalGeral || 0) <= 0) {
    return;
  }

  const numeroPagamento = `PAG-${compra.numeroDocumento}`;
  await criarPagamentoCompra({
    empresaId: compra.empresaId,
    fornecedorId: compra.fornecedorId,
    compraId: compra.id,
    numeroDocumento: numeroPagamento,
    dataEmissao: compra.dataEmissao,
    valor: Number(compra.totalGeral || 0),
    metodoPagamento: 'Outro',
    referencia: compra.numeroDocumento,
    observacoes: `Liquidacao automatica do documento ${compra.tipoDocumento} ${compra.numeroDocumento}`,
    origem: 'documento_compra_imediato',
    automatico: true,
    contabilizarSeparado: false,
    criadoPor: dados?.criadoPor || compra.criadoPor,
  });
}

async function reverterMovimentoEntradaCompraSemLote(movimento: any): Promise<void> {
  if (!movimento?.id) return;

  if (movimento.armazemId) {
    const resultadoStock = await stockArmazem.atualizarStockArmazem({
      empresaId: movimento.empresaId,
      armazemId: movimento.armazemId,
      armazemCodigo: movimento.armazemCodigo || '',
      armazemNome: movimento.armazemNome || '',
      artigoId: movimento.artigoId,
      artigoCodigo: movimento.artigoCodigo || '',
      artigoNome: movimento.artigoNome || movimento.artigoCodigo || '',
      quantidadeDelta: -Number(movimento.quantidade || 0),
    });
    if (!resultadoStock.success) {
      throw new Error(resultadoStock.error || 'Falha ao reverter stock da recepcao');
    }

    const stockTotal = await stockArmazem.obterStockTotalArtigo(movimento.empresaId, movimento.artigoId);
    const resultadoArtigo = await artigos.atualizarEstoque(movimento.artigoId, stockTotal, 'definir');
    if (!resultadoArtigo.success) {
      throw new Error(resultadoArtigo.error || 'Falha ao sincronizar stock do artigo');
    }
  } else {
    const resultadoArtigo = await artigos.atualizarEstoque(movimento.artigoId, Number(movimento.quantidade || 0), 'remover');
    if (!resultadoArtigo.success) {
      throw new Error(resultadoArtigo.error || 'Falha ao reverter stock do artigo');
    }
  }

  await kv.del(`movimento_stock:${movimento.id}`);
}
function normalizarTexto(valor?: string): string {
  return (valor || '').trim().toLowerCase();
}

function linhaCompraPreenchida(linha?: Partial<LinhaCompra> | null): linha is LinhaCompra {
  if (!linha) return false;
  return Boolean(
    normalizarTexto(linha.codigo) ||
    normalizarTexto(linha.descricao) ||
    Number(linha.quantidade || 0) > 0 ||
    Number(linha.precoUnitario || 0) > 0,
  );
}

function criarErroLinha(indice: number, mensagem: string) {
  return `Linha ${indice + 1}: ${mensagem}`;
}

async function prepararLinhasDocumentoCompra(
  dados: DocumentoCompraProcessamentoInput,
): Promise<{ success: boolean; data?: LinhaCompra[]; error?: string }> {
  const perfilDocumento = obterPerfilDocumentoCompra(dados.tipoDocumento);
  const linhasValidas = (dados.linhas || []).filter(linhaCompraPreenchida);
  if (linhasValidas.length === 0) {
    return { success: false, error: 'Informe pelo menos uma linha válida no documento de compra' };
  }

  // ✅ Mesma regra ja aplicada do lado das vendas (validacao-fiscal.tsx): uma
  // empresa num regime sem direito a deducao de IVA nao pode registar IVA
  // dedutivel numa compra — o valor do IVA do fornecedor tem de ser
  // capitalizado no custo, nao lancado como credito fiscal.
  const regimeFiscalEmpresa = await buscarRegimeFiscalEmpresa(dados.empresaId);
  const empresaSemDireitoDeducaoIva = Boolean(regimeFiscalEmpresa && REGIMES_SEM_IVA.includes(regimeFiscalEmpresa));

  const detalhesMap = new Map((dados.detalhesLinhas || []).map((item) => [item.linhaId, item]));
  const erros: string[] = [];
  const linhasProcessadas: LinhaCompra[] = [];

  for (let indice = 0; indice < linhasValidas.length; indice += 1) {
    const linha = linhasValidas[indice];
    const detalhe = detalhesMap.get(linha.id);
    const codigo = (linha.codigo || '').trim().toUpperCase();
    const descricao = (linha.descricao || '').trim();
    const unidade = (linha.unidade || '').trim();
    const quantidade = Number(linha.quantidade || 0);
    const precoUnitario = Number(linha.precoUnitario || 0);
    const desconto = Number(linha.desconto || 0);
    const iva = Number(linha.iva || 0);
    const subtotal = Number(linha.subtotal || 0);

    if (!codigo) erros.push(criarErroLinha(indice, 'Código é obrigatório'));
    if (!descricao) erros.push(criarErroLinha(indice, 'Descrição é obrigatória'));
    if (!unidade) erros.push(criarErroLinha(indice, 'Unidade é obrigatória'));
    if (!Number.isFinite(quantidade) || quantidade <= 0) erros.push(criarErroLinha(indice, 'Quantidade deve ser maior que zero'));
    if (!Number.isFinite(precoUnitario) || precoUnitario < 0) erros.push(criarErroLinha(indice, 'Valor unitário inválido'));
    if (!Number.isFinite(desconto) || desconto < 0 || desconto > 100) erros.push(criarErroLinha(indice, 'Desconto inválido'));
    if (!Number.isFinite(iva) || iva < 0) erros.push(criarErroLinha(indice, 'IVA inválido'));
    if (empresaSemDireitoDeducaoIva && iva > 0) {
      erros.push(criarErroLinha(indice, `A empresa esta no regime fiscal "${regimeFiscalEmpresa}" e nao pode deduzir IVA. Corrija a taxa de IVA desta linha para 0%`));
    }

    const artigoExistente = codigo
      ? await artigos.buscarArtigoPorCodigo(dados.empresaId, codigo)
      : null;

    const tipoArtigo = detalhe?.tipo || linha.tipoArtigo || artigoExistente?.tipo || 'produto';
    const armazemLinha = detalhe?.armazemId || linha.armazemId || dados.armazemId || artigoExistente?.armazemId;

    if (tipoArtigo === 'produto' && perfilDocumento.exigeArmazem && !armazemLinha) {
      erros.push(criarErroLinha(indice, 'Armazém de destino é obrigatório para produtos com stock'));
    }

    linhasProcessadas.push({
      ...linha,
      codigo,
      descricao,
      unidade,
      quantidade,
      precoUnitario,
      valorUnitario: precoUnitario,
      desconto,
      iva,
      subtotal,
      tipoArtigo,
      precoVenda: detalhe?.precoVenda ?? linha.precoVenda ?? artigoExistente?.precoVenda ?? precoUnitario,
      codigoBarras: detalhe?.codigoBarras ?? linha.codigoBarras ?? artigoExistente?.codigoBarras,
      dataValidade: tipoArtigo === 'produto' ? (detalhe?.dataValidade || linha.dataValidade || artigoExistente?.dataValidade) : undefined,
      lote: tipoArtigo === 'produto' ? (detalhe?.lote || linha.lote) : undefined,
      armazemId: tipoArtigo === 'produto' ? armazemLinha : undefined,
      imagemUrl: detalhe?.imagemUrl || linha.imagemUrl || artigoExistente?.imagemUrl,
    });
  }

  if (erros.length > 0) {
    return { success: false, error: `Há erro em uma ou mais linhas do documento: ${erros.join(' | ')}` };
  }

  return { success: true, data: linhasProcessadas };
}

async function limparMovimentosDocumentoSemReverter(
  empresaId: string,
  documentoNumero: string,
  documentoTipo?: string,
): Promise<{ success: boolean; error?: string }> {
  try {
    const movimentos = await kv.getByPrefixWithKeys<any>('movimento_stock:');

    for (const item of movimentos) {
      const movimento = item.value;
      if (
        movimento &&
        movimento.empresaId === empresaId &&
        movimento.documentoNumero === documentoNumero &&
        documentoTipoCorrespondeCompra(movimento.documentoTipo, documentoTipo)
      ) {
        await kv.del(item.key);
      }
    }

    return { success: true };
  } catch (error: any) {
    console.error('[Compras] Erro ao limpar movimentos do documento:', error);
    return { success: false, error: error.message };
  }
}

async function limparVinculoDocumentoArtigoSeNecessario(
  artigoId: string,
  numeroDocumento: string,
  tipoDocumento?: string,
): Promise<void> {
  const artigo = await artigos.buscarArtigoPorId(artigoId);
  if (!artigo) return;

  if (
    artigo.numeroDocumento === numeroDocumento &&
    (!tipoDocumento || artigo.tipoDocumento === tipoDocumento)
  ) {
    await artigos.atualizarArtigo(artigoId, {
      numeroDocumento: undefined,
      tipoDocumento: undefined,
      dataDocumento: undefined,
    });
  }
}

async function reverterLinhaDocumentoCompra(
  documento: DocumentoCompraComLinhasParaReversao,
  linha: LinhaCompra,
): Promise<{ success: boolean; error?: string }> {
  if (!linha.artigoId) {
    return { success: true };
  }

  const artigo = await artigos.buscarArtigoPorId(linha.artigoId);
  if (!artigo) {
    return { success: true };
  }

  if ((linha.tipoArtigo || artigo.tipo) === 'servico') {
    await limparVinculoDocumentoArtigoSeNecessario(linha.artigoId, documento.numeroDocumento, documento.tipoDocumento);
    return { success: true };
  }

  const quantidadeRecebida = obterQuantidadeRecebidaLinha(linha);
  if (quantidadeRecebida <= 0) {
    await limparVinculoDocumentoArtigoSeNecessario(linha.artigoId, documento.numeroDocumento, documento.tipoDocumento);
    return { success: true };
  }

  const recepcoes = (linha.recepcoes || []).filter((recepcao) => Number(recepcao.quantidade || 0) > 0);
  const recepcoesParaReverter = recepcoes.length > 0
    ? recepcoes
    : [{
        id: `recepcao_reversao_${linha.id}`,
        linhaId: linha.id,
        quantidade: quantidadeRecebida,
        lote: linha.lote,
        dataValidade: linha.dataValidade,
        dataFabricacao: linha.dataFabricacao,
        armazemId: linha.armazemId || documento.armazemId || artigo.armazemId || '',
        recebidoEm: documento.recepcionadoEm || documento.dataCriacao || new Date().toISOString(),
        recebidoPor: documento.recepcionadoPor,
      }];

  let usouStockArmazem = false;

  for (const recepcao of recepcoesParaReverter) {
    const quantidade = Number(recepcao.quantidade || 0);
    if (quantidade <= 0) continue;

    const armazemId = recepcao.armazemId || linha.armazemId || documento.armazemId || artigo.armazemId;

    if (armazemId) {
      const armazem = await buscarArmazemPorId(armazemId);
      if (!armazem) {
        return { success: false, error: `Armazém ${armazemId} não encontrado para reverter a linha ${linha.codigo}` };
      }

      const loteExistente = await stockLotes.buscarLotePorIdentidade(
        documento.empresaId,
        linha.artigoId,
        armazemId,
        recepcao.lote || linha.lote,
        recepcao.dataValidade || linha.dataValidade,
      );
      const novaQuantidadeLote = loteExistente ? loteExistente.quantidade - quantidade : undefined;

      if (loteExistente && novaQuantidadeLote !== undefined) {
        if (novaQuantidadeLote < 0) {
          return { success: false, error: `Lote ${loteExistente.lote || loteExistente.id} sem saldo suficiente para reverter a linha ${linha.codigo}` };
        }

        if (novaQuantidadeLote < loteExistente.quantidadeReservada) {
          return { success: false, error: `Lote ${loteExistente.lote || loteExistente.id} possui reserva superior ao saldo apos a reversao da linha ${linha.codigo}` };
        }
      }

      const resultadoStock = await stockArmazem.atualizarStockArmazem({
        empresaId: documento.empresaId,
        armazemId,
        armazemCodigo: armazem.codigo,
        armazemNome: armazem.nome,
        artigoId: linha.artigoId,
        artigoCodigo: artigo.codigo,
        artigoNome: artigo.nome || artigo.codigo,
        quantidadeDelta: -quantidade,
      });

      if (!resultadoStock.success) {
        return { success: false, error: resultadoStock.error || `Falha ao reverter stock da linha ${linha.codigo}` };
      }

      usouStockArmazem = true;

      if (loteExistente && novaQuantidadeLote !== undefined) {
        try {
          await stockLotes.upsertLote({
            empresaId: loteExistente.empresaId,
            artigoId: loteExistente.artigoId,
            armazemId: loteExistente.armazemId,
            lote: loteExistente.lote,
            dataValidade: loteExistente.dataValidade,
            dataFabricacao: loteExistente.dataFabricacao,
            quantidade: novaQuantidadeLote,
            quantidadeReservada: loteExistente.quantidadeReservada,
            custoUnitario: loteExistente.custoUnitario,
            fornecedorId: loteExistente.fornecedorId,
            documentoCompraId: loteExistente.documentoCompraId,
            localizacao: loteExistente.localizacao,
            status: loteExistente.status,
          });
        } catch (error: any) {
          await stockArmazem.atualizarStockArmazem({
            empresaId: documento.empresaId,
            armazemId,
            armazemCodigo: armazem.codigo,
            armazemNome: armazem.nome,
            artigoId: linha.artigoId,
            artigoCodigo: artigo.codigo,
            artigoNome: artigo.nome || artigo.codigo,
            quantidadeDelta: quantidade,
          });

          return { success: false, error: `Falha ao reverter lote da linha ${linha.codigo}: ${error.message || error}` };
        }
      }
    } else {
      const resultadoEstoque = await artigos.atualizarEstoque(linha.artigoId, quantidade, 'remover');
      if (!resultadoEstoque.success) {
        return { success: false, error: resultadoEstoque.error || `Falha ao reverter stock da linha ${linha.codigo}` };
      }
    }
  }

  if (usouStockArmazem) {
    const stockTotal = await stockArmazem.obterStockTotalArtigo(documento.empresaId, linha.artigoId);
    const resultadoArtigo = await artigos.atualizarEstoque(linha.artigoId, stockTotal, 'definir');
    if (!resultadoArtigo.success) {
      return { success: false, error: resultadoArtigo.error || `Falha ao sincronizar stock total do artigo ${linha.codigo}` };
    }
  }

  await limparVinculoDocumentoArtigoSeNecessario(linha.artigoId, documento.numeroDocumento, documento.tipoDocumento);
  return { success: true };
}

async function reverterMovimentosSaidaDocumentoCompra(
  documento: DocumentoCompraComLinhasParaReversao,
): Promise<{ success: boolean; error?: string }> {
  const movimentos = await movimentosStock.listarMovimentos(documento.empresaId);
  const movimentosDocumento = movimentos.filter((movimento: any) =>
    movimento &&
    movimento.documentoNumero === documento.numeroDocumento &&
    documentoTipoCorrespondeCompra(movimento.documentoTipo, documento.tipoDocumento)
  );

  for (const movimento of movimentosDocumento.reverse()) {
    const resultado = await movimentosStock.deletarMovimento(movimento.id);
    if (!resultado.success) {
      return { success: false, error: resultado.error || `Falha ao reverter movimento ${movimento.id}` };
    }
  }

  for (const linha of documento.linhas || []) {
    if (linha.artigoId) {
      await limparVinculoDocumentoArtigoSeNecessario(linha.artigoId, documento.numeroDocumento, documento.tipoDocumento);
    }
  }

  return { success: true };
}

async function reverterEfeitoDocumentoCompra(
  documento: DocumentoCompraComLinhasParaReversao,
): Promise<{ success: boolean; error?: string }> {
  const perfilDocumento = obterPerfilDocumentoCompra(documento.tipoDocumento);
  if (perfilDocumento.efeitoStock === 'saida') {
    return await reverterMovimentosSaidaDocumentoCompra(documento);
  }

  for (const linha of documento.linhas || []) {
    const resultado = await reverterLinhaDocumentoCompra(documento, linha);
    if (!resultado.success) {
      return resultado;
    }
  }

  return { success: true };
}

async function materializarLinhasDocumentoCompra(
  dados: DocumentoCompraProcessamentoInput,
  linhasProcessadas: LinhaCompra[],
): Promise<{ success: boolean; data?: LinhaCompra[]; error?: string }> {
  const perfilDocumento = obterPerfilDocumentoCompra(dados.tipoDocumento);
  const linhasDocumento: LinhaCompra[] = [];

  try {
    for (let indice = 0; indice < linhasProcessadas.length; indice += 1) {
      const linha = linhasProcessadas[indice];

      if (perfilDocumento.efeitoStock === 'saida' && linha.tipoArtigo !== 'servico') {
        const artigoExistente = await artigos.buscarArtigoPorCodigo(dados.empresaId, linha.codigo);
        if (!artigoExistente) {
          return {
            success: false,
            error: `HÃ¡ erro em uma ou mais linhas do documento. ${criarErroLinha(indice, `Artigo ${linha.codigo} nao encontrado para devolucao/nota de credito`)}`,
          };
        }

        const armazemId = linha.armazemId || dados.armazemId || artigoExistente.armazemId;
        if (!armazemId) {
          return {
            success: false,
            error: `HÃ¡ erro em uma ou mais linhas do documento. ${criarErroLinha(indice, `Defina o armazem da saida para o artigo ${linha.codigo}`)}`,
          };
        }

        const resultadoMovimento = await movimentosStock.criarMovimento({
          empresaId: dados.empresaId,
          artigoId: artigoExistente.id,
          tipo: 'saida',
          quantidade: linha.quantidade,
          motivo: 'devolucao_fornecedor',
          armazemId,
          lote: linha.lote,
          custoUnitario: linha.precoUnitario,
          documentoTipo: dados.tipoDocumento,
          documentoNumero: dados.numeroDocumento,
          observacoes: `Devolucao/nota de credito de fornecedor ${dados.numeroDocumento}`,
          responsavel: dados.criadoPor,
          dataMovimento: dados.dataEmissao,
        });

        if (!resultadoMovimento.success || !resultadoMovimento.data) {
          return {
            success: false,
            error: `HÃ¡ erro em uma ou mais linhas do documento. ${criarErroLinha(indice, resultadoMovimento.error || `Falha ao baixar stock do artigo ${linha.codigo}`)}`,
          };
        }

        linhasDocumento.push({
          ...linha,
          artigoId: artigoExistente.id,
          quantidadeRecebida: 0,
          recepcoes: [],
        });
        continue;
      }

      const quantidadeEntradaStock = perfilDocumento.efeitoStock === 'entrada' && linha.tipoArtigo === 'produto'
        ? linha.quantidade
        : 0;

      const resultadoArtigo = await artigos.criarArtigo({
        empresaId: dados.empresaId,
        codigo: linha.codigo,
        nome: linha.descricao,
        descricao: linha.descricao,
        tipo: linha.tipoArtigo || 'produto',
        unidade: linha.unidade as artigos.UnidadeArtigo,
        precoCompra: linha.precoUnitario,
        precoVenda: linha.precoVenda ?? linha.precoUnitario,
        iva: linha.iva,
        ivaIncluso: linha.ivaIncluso,
        ivaIncluidoNaoLiquidado: linha.ivaIncluidoNaoLiquidado,
        desconto: linha.desconto,
        fornecedorId: dados.fornecedorId,
        fornecedorNome: dados.fornecedorNome,
        fornecedorCodigo: dados.fornecedorCodigo,
        fornecedorNuit: dados.fornecedorNuit,
        armazemId: linha.tipoArtigo === 'produto' ? linha.armazemId : undefined,
        estoqueAtual: quantidadeEntradaStock,
        dataValidade: linha.tipoArtigo === 'produto' ? linha.dataValidade : undefined,
        lote: linha.tipoArtigo === 'produto' ? linha.lote : undefined,
        codigoBarras: linha.codigoBarras,
        imagemUrl: linha.imagemUrl,
        numeroDocumento: dados.numeroDocumento,
        tipoDocumento: dados.tipoDocumento,
        dataDocumento: dados.dataEmissao,
        observacoes: dados.observacoes,
        ativo: true,
      });

      if (!resultadoArtigo.success || !resultadoArtigo.data) {
        return {
          success: false,
          error: `Há erro em uma ou mais linhas do documento. ${criarErroLinha(indice, resultadoArtigo.error || `Falha ao processar o artigo ${linha.codigo}`)}`,
        };
      }

      linhasDocumento.push({
        ...linha,
        artigoId: resultadoArtigo.data.id,
        quantidadeRecebida: quantidadeEntradaStock,
        recepcoes: quantidadeEntradaStock > 0
          ? [{
              id: `recepcao_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
              linhaId: linha.id,
              quantidade: quantidadeEntradaStock,
              lote: resultadoArtigo.data.lote || linha.lote,
              dataValidade: linha.dataValidade,
              armazemId: linha.armazemId || dados.armazemId || '',
              recebidoEm: new Date().toISOString(),
              recebidoPor: dados.criadoPor,
            }]
          : [],
      });
    }

    return { success: true, data: linhasDocumento };
  } catch (error: any) {
    console.error('[Compras] Erro ao materializar linhas do documento:', error);
    return { success: false, error: error.message };
  } finally {
    if (linhasDocumento.length > 0) {
      const ultimaTentativaFalhou = linhasDocumento.length !== linhasProcessadas.length;
      if (ultimaTentativaFalhou) {
        await reverterEfeitoDocumentoCompra({
          empresaId: dados.empresaId,
          numeroDocumento: dados.numeroDocumento,
          tipoDocumento: dados.tipoDocumento,
          armazemId: dados.armazemId,
          recepcionadoEm: new Date().toISOString(),
          recepcionadoPor: dados.criadoPor,
          dataCriacao: new Date().toISOString(),
          linhas: linhasDocumento,
        });
        await limparMovimentosDocumentoSemReverter(dados.empresaId, dados.numeroDocumento, dados.tipoDocumento);
      }
    }
  }
}

export async function criarCompra(dados: Omit<Compra, 'id' | 'dataCriacao'>): Promise<{ success: boolean; data?: Compra; error?: string; warning?: string }> {
  try {
    if (!dados.empresaId || !dados.fornecedorId || !dados.numeroDocumento) {
      return { success: false, error: 'Empresa, fornecedor e numero do documento sao obrigatorios' };
    }

    // ✅ Mesma regra do lado das vendas (validacao-fiscal.tsx) — esta rota
    // recebe as linhas ja processadas pelo cliente (ao contrario de
    // processarDocumentoCompra, que passa por prepararLinhasDocumentoCompra),
    // por isso precisa da sua propria validacao de regime fiscal.
    const regimeFiscalEmpresaCriarCompra = await buscarRegimeFiscalEmpresa(dados.empresaId);
    if (regimeFiscalEmpresaCriarCompra && REGIMES_SEM_IVA.includes(regimeFiscalEmpresaCriarCompra)) {
      const linhaComIva = (dados.linhas || []).find((linha: any) => Number(linha?.iva || 0) > 0);
      if (linhaComIva) {
        return {
          success: false,
          error: `A empresa esta no regime fiscal "${regimeFiscalEmpresaCriarCompra}" e nao pode deduzir IVA. Corrija a taxa de IVA das linhas do documento para 0%.`,
        };
      }
    }

    const perfilDocumento = obterPerfilDocumentoCompra(dados.tipoDocumento);
    const exercicio = await exerciciosEconomicos.validarExercicioAberto(
      dados.empresaId,
      dados.dataEmissao,
      `documento de compra ${dados.tipoDocumento}`,
    );

    const compraExistente = await buscarCompraPorNumero(dados.empresaId, dados.numeroDocumento, dados.fornecedorId);
    if (compraExistente) {
      return { success: false, error: 'Ja existe uma compra com este numero de documento' };
    }

    const comprasExistentes = await listarCompras(dados.empresaId);
    validarDataEmissaoCronologica(dados, comprasExistentes, {
      rotuloDocumento: `Documento de Compra ${dados.tipoDocumento}`,
      tipo: dados.tipoDocumento,
    });

    const id = `compra_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    // ✅ ...dados vem ANTES de id: mesmo bug e correcao de clientes.tsx/
    // fornecedores.tsx (criarCliente/criarFornecedor) — um id vindo no corpo
    // do pedido (ex: rota POST /empresas/:id/compras chamada directamente,
    // fora do fluxo normal de processar-documento) nao pode sobrepor-se ao
    // id gerado aqui no servidor.
    const compra: Compra = {
      ...dados,
      id,
      exercicioEconomicoId: exercicio.id,
      anoExercicio: exercicio.ano,
      numeroInterno: dados.numeroInterno || await gerarProximoNumeroInternoCompra(
        dados.empresaId,
        comprasExistentes,
        exercicio.ano,
      ),
      estado: dados.estado || obterEstadoInicialDocumentoCompra(perfilDocumento),
      recepcaoStatus: dados.recepcaoStatus || 'nao_recepcionada',
      movimentaStock: dados.movimentaStock ?? perfilDocumento.movimentaStock,
      geraLancamentoContabil: dados.geraLancamentoContabil ?? perfilDocumento.geraLancamentoContabil,
      geraContaPagar: dados.geraContaPagar ?? perfilDocumento.geraContaPagar,
      liquidacaoImediata: dados.liquidacaoImediata ?? perfilDocumento.liquidacaoImediata,
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`compra:${id}`, compra);

    const comprasEmpresa = await kv.get(`compras_empresa:${dados.empresaId}`) || [];
    comprasEmpresa.push(id);
    await kv.set(`compras_empresa:${dados.empresaId}`, comprasEmpresa);

    const comprasFornecedor = await kv.get(`compras_fornecedor:${dados.fornecedorId}`) || [];
    comprasFornecedor.push(id);
    await kv.set(`compras_fornecedor:${dados.fornecedorId}`, comprasFornecedor);

    console.log(`[Compras] Compra criada: ${dados.numeroDocumento}`);

    // ✅ Nao existe (ainda) um mecanismo de liquidacao automatica de
    // adiantamentos a fornecedor contra compras reais — o saldo fica sempre
    // por aplicar e o lancamento desta nova compra regista uma divida cheia,
    // sem descontar o adiantamento. Avisa em vez de aplicar automaticamente
    // (evita mexer em dinheiro/saldo sem confirmacao explicita do utilizador).
    let warning: string | undefined;
    const saldoAdiantamentos = await obterSaldoAdiantamentosFornecedor(dados.fornecedorId);
    if (saldoAdiantamentos > 0) {
      warning = `Este fornecedor tem ${saldoAdiantamentos.toFixed(2)} em adiantamento(s) ainda por aplicar a nenhuma compra. Reconcilie manualmente para nao pagar em duplicado.`;
    }

    return { success: true, data: compra, warning };
  } catch (error: any) {
    console.error('[Compras] Erro ao criar compra:', error);
    return { success: false, error: error.message };
  }
}

export async function processarDocumentoCompra(
  dados: DocumentoCompraProcessamentoInput,
): Promise<{ success: boolean; data?: Compra; error?: string; warning?: string }> {
  try {
    const perfilDocumento = obterPerfilDocumentoCompra(dados.tipoDocumento);
    if (!dados.empresaId || !dados.fornecedorId || !dados.numeroDocumento || !dados.dataEmissao) {
      return { success: false, error: 'Fornecedor, número e data do documento são obrigatórios' };
    }

    const compraExistente = await buscarCompraPorNumero(dados.empresaId, dados.numeroDocumento, dados.fornecedorId);
    if (compraExistente) {
      return { success: false, error: 'Já existe um documento de compra com este número para este fornecedor' };
    }

    const comprasExistentes = await listarCompras(dados.empresaId);
    validarDataEmissaoCronologica(dados, comprasExistentes, {
      rotuloDocumento: `Documento de Compra ${dados.tipoDocumento}`,
      tipo: dados.tipoDocumento,
    });

    const linhasPreparadas = await prepararLinhasDocumentoCompra(dados);
    if (!linhasPreparadas.success || !linhasPreparadas.data) {
      return { success: false, error: linhasPreparadas.error };
    }

    const linhasDocumentoResultado = await materializarLinhasDocumentoCompra(dados, linhasPreparadas.data);
    if (!linhasDocumentoResultado.success || !linhasDocumentoResultado.data) {
      return { success: false, error: linhasDocumentoResultado.error };
    }

    const linhasDocumento = linhasDocumentoResultado.data;
    const temEntradaProdutos = perfilDocumento.efeitoStock === 'entrada' && linhasDocumento.some((linha) => linha.tipoArtigo === 'produto');

    const compraResultado = await criarCompra({
      empresaId: dados.empresaId,
      fornecedorId: dados.fornecedorId,
      numeroDocumento: dados.numeroDocumento,
      tipoDocumento: dados.tipoDocumento,
      dataEmissao: dados.dataEmissao,
      dataVencimento: dados.dataVencimento,
      linhas: linhasDocumento,
      subtotal: dados.subtotal,
      descontoGlobal: dados.descontoGlobal,
      totalIVA: dados.totalIVA,
      totalGeral: dados.totalGeral,
      estado: obterEstadoInicialDocumentoCompra(perfilDocumento),
      observacoes: dados.observacoes,
      armazemId: dados.armazemId,
      recepcaoStatus: temEntradaProdutos
        ? 'recepcionada'
        : 'nao_recepcionada',
      movimentaStock: perfilDocumento.movimentaStock,
      geraLancamentoContabil: perfilDocumento.geraLancamentoContabil,
      geraContaPagar: perfilDocumento.geraContaPagar,
      liquidacaoImediata: perfilDocumento.liquidacaoImediata,
      recepcionadoEm: temEntradaProdutos
        ? new Date().toISOString()
        : undefined,
      recepcionadoPor: dados.criadoPor,
      criadoPor: dados.criadoPor,
    });

    if (!compraResultado.success || !compraResultado.data) {
      await reverterEfeitoDocumentoCompra({
        empresaId: dados.empresaId,
        numeroDocumento: dados.numeroDocumento,
        tipoDocumento: dados.tipoDocumento,
        armazemId: dados.armazemId,
        recepcionadoEm: new Date().toISOString(),
        recepcionadoPor: dados.criadoPor,
        dataCriacao: new Date().toISOString(),
        linhas: linhasDocumento,
      });
      await limparMovimentosDocumentoSemReverter(dados.empresaId, dados.numeroDocumento, dados.tipoDocumento);

      return { success: false, error: compraResultado.error || 'Falha ao gravar o documento de compra' };
    }

    await sincronizarPagamentoImediatoCompra(compraResultado.data, dados);
    const compraAtualizada = await buscarCompraPorId(compraResultado.data.id);

    return { success: true, data: compraAtualizada || compraResultado.data, warning: compraResultado.warning };
  } catch (error: any) {
    console.error('[Compras] Erro ao processar documento completo:', error);
    return { success: false, error: error.message };
  }
}

export async function reprocessarDocumentoCompraExistente(
  id: string,
  dados: DocumentoCompraProcessamentoInput,
): Promise<{ success: boolean; data?: Compra; error?: string }> {
  const compraExistente = await buscarCompraPorId(id);
  if (!compraExistente) {
    return { success: false, error: 'Compra nao encontrada' };
  }

  try {
    const perfilDocumento = obterPerfilDocumentoCompra(dados.tipoDocumento);
    if (!dados.empresaId || !dados.fornecedorId || !dados.numeroDocumento || !dados.dataEmissao) {
      return { success: false, error: 'Fornecedor, número e data do documento são obrigatórios' };
    }

    const compraDuplicada = await buscarCompraPorNumero(dados.empresaId, dados.numeroDocumento, dados.fornecedorId);
    if (compraDuplicada && compraDuplicada.id !== id) {
      return { success: false, error: 'Já existe um documento de compra com este número para este fornecedor' };
    }


    const pagamentosAssociados = await listarPagamentosAssociadosCompra(compraExistente);
    const pagamentosManuais = pagamentosAssociados.filter((pagamento) => !pagamentoCompraAutomatico(pagamento));
    const totalPago = somarPagamentosCompra(pagamentosManuais);

    if (pagamentosManuais.length > 0 && dados.fornecedorId !== compraExistente.fornecedorId) {
      return { success: false, error: 'Nao e possivel alterar o fornecedor de uma compra com pagamentos associados' };
    }

    if (totalPago > Number(dados.totalGeral || 0) + 0.0001) {
      return { success: false, error: `Esta compra ja possui pagamentos de ${totalPago.toFixed(2)} MT, superiores ao novo total do documento` };
    }

    const linhasPreparadas = await prepararLinhasDocumentoCompra(dados);
    if (!linhasPreparadas.success || !linhasPreparadas.data) {
      return { success: false, error: linhasPreparadas.error };
    }

    const reversaoAnterior = await reverterEfeitoDocumentoCompra(compraExistente);
    if (!reversaoAnterior.success) {
      return { success: false, error: reversaoAnterior.error || 'Falha ao reverter o documento anterior' };
    }

    const limpezaAnterior = await limparMovimentosDocumentoSemReverter(
      compraExistente.empresaId,
      compraExistente.numeroDocumento,
      compraExistente.tipoDocumento,
    );
    if (!limpezaAnterior.success) {
      return { success: false, error: limpezaAnterior.error || 'Falha ao limpar movimentos anteriores' };
    }

    const linhasDocumentoResultado = await materializarLinhasDocumentoCompra(dados, linhasPreparadas.data);
    if (!linhasDocumentoResultado.success || !linhasDocumentoResultado.data) {
      await materializarLinhasDocumentoCompra({
        empresaId: compraExistente.empresaId,
        fornecedorId: compraExistente.fornecedorId,
        numeroDocumento: compraExistente.numeroDocumento,
        tipoDocumento: compraExistente.tipoDocumento,
        dataEmissao: compraExistente.dataEmissao,
        dataVencimento: compraExistente.dataVencimento,
        linhas: compraExistente.linhas,
        detalhesLinhas: compraExistente.linhas.map((linha) => ({
          linhaId: linha.id,
          tipo: linha.tipoArtigo,
          precoVenda: linha.precoVenda,
          codigoBarras: linha.codigoBarras,
          dataValidade: linha.dataValidade,
          lote: linha.lote,
          armazemId: linha.armazemId,
          imagemUrl: linha.imagemUrl,
        })),
        subtotal: compraExistente.subtotal,
        descontoGlobal: compraExistente.descontoGlobal,
        totalIVA: compraExistente.totalIVA,
        totalGeral: compraExistente.totalGeral,
        observacoes: compraExistente.observacoes,
        armazemId: compraExistente.armazemId,
        criadoPor: compraExistente.criadoPor,
      }, compraExistente.linhas.filter(linhaCompraPreenchida));

      return { success: false, error: linhasDocumentoResultado.error };
    }

    await removerPagamentosAutomaticosCompra(compraExistente);

    const linhasDocumento = linhasDocumentoResultado.data;
    const agora = new Date().toISOString();
    const temProdutos = perfilDocumento.efeitoStock === 'entrada' && linhasDocumento.some((linha) => linha.tipoArtigo === 'produto');

    const compraAtualizada = await atualizarCompra(id, {
      fornecedorId: dados.fornecedorId,
      numeroDocumento: dados.numeroDocumento,
      tipoDocumento: dados.tipoDocumento,
      dataEmissao: dados.dataEmissao,
      dataVencimento: dados.dataVencimento,
      linhas: linhasDocumento,
      subtotal: dados.subtotal,
      descontoGlobal: dados.descontoGlobal,
      totalIVA: dados.totalIVA,
      totalGeral: dados.totalGeral,
      observacoes: dados.observacoes,
      armazemId: dados.armazemId,
      estado: obterEstadoInicialDocumentoCompra(perfilDocumento),
      recepcaoStatus: temProdutos ? 'recepcionada' : 'nao_recepcionada',
      movimentaStock: perfilDocumento.movimentaStock,
      geraLancamentoContabil: perfilDocumento.geraLancamentoContabil,
      geraContaPagar: perfilDocumento.geraContaPagar,
      liquidacaoImediata: perfilDocumento.liquidacaoImediata,
      recepcionadoEm: temProdutos ? agora : undefined,
      recepcionadoPor: dados.criadoPor || compraExistente.recepcionadoPor,
      criadoPor: compraExistente.criadoPor || dados.criadoPor,
    });

    if (!compraAtualizada.success || !compraAtualizada.data) {
      await reverterEfeitoDocumentoCompra({
        empresaId: dados.empresaId,
        numeroDocumento: dados.numeroDocumento,
        tipoDocumento: dados.tipoDocumento,
        armazemId: dados.armazemId,
        recepcionadoEm: agora,
        recepcionadoPor: dados.criadoPor,
        dataCriacao: agora,
        linhas: linhasDocumento,
      });
      await limparMovimentosDocumentoSemReverter(dados.empresaId, dados.numeroDocumento, dados.tipoDocumento);
      await materializarLinhasDocumentoCompra({
        empresaId: compraExistente.empresaId,
        fornecedorId: compraExistente.fornecedorId,
        numeroDocumento: compraExistente.numeroDocumento,
        tipoDocumento: compraExistente.tipoDocumento,
        dataEmissao: compraExistente.dataEmissao,
        dataVencimento: compraExistente.dataVencimento,
        linhas: compraExistente.linhas,
        detalhesLinhas: compraExistente.linhas.map((linha) => ({
          linhaId: linha.id,
          tipo: linha.tipoArtigo,
          precoVenda: linha.precoVenda,
          codigoBarras: linha.codigoBarras,
          dataValidade: linha.dataValidade,
          lote: linha.lote,
          armazemId: linha.armazemId,
          imagemUrl: linha.imagemUrl,
        })),
        subtotal: compraExistente.subtotal,
        descontoGlobal: compraExistente.descontoGlobal,
        totalIVA: compraExistente.totalIVA,
        totalGeral: compraExistente.totalGeral,
        observacoes: compraExistente.observacoes,
        armazemId: compraExistente.armazemId,
        criadoPor: compraExistente.criadoPor,
      }, compraExistente.linhas.filter(linhaCompraPreenchida));
      await sincronizarPagamentoImediatoCompra(compraExistente);

      return { success: false, error: compraAtualizada.error || 'Falha ao atualizar o documento de compra' };
    }

    await sincronizarPagamentoImediatoCompra(compraAtualizada.data, dados);
    const compraAtualizadaComPagamento = await buscarCompraPorId(compraAtualizada.data.id);

    return { success: true, data: compraAtualizadaComPagamento || compraAtualizada.data };
  } catch (error: any) {
    console.error('[Compras] Erro ao reprocessar documento existente:', error);
    return { success: false, error: error.message };
  }
}

export async function buscarCompraPorNumero(empresaId: string, numeroDocumento: string, fornecedorId?: string): Promise<Compra | null> {
  try {
    const comprasEmpresa = await listarCompras(empresaId);
    return comprasEmpresa.find((compra) =>
      compra &&
      compra.numeroDocumento === numeroDocumento &&
      (!fornecedorId || compra.fornecedorId === fornecedorId)
    ) || null;
  } catch (error) {
    console.error('[Compras] Erro ao buscar compra por numero:', error);
    return null;
  }
}

export async function buscarCompraPorId(id: string): Promise<Compra | null> {
  try {
    const compra = await kv.get(`compra:${id}`) as Compra | null;
    if (!compra) {
      return null;
    }

    const comprasEmpresa = await listarCompras(compra.empresaId);
    return comprasEmpresa.find((item) => item.id === id) || compra;
  } catch (error) {
    console.error('[Compras] Erro ao buscar compra por ID:', error);
    return null;
  }
}

export async function atualizarCompra(
  id: string,
  dados: Partial<Compra>
): Promise<{ success: boolean; data?: Compra; error?: string }> {
  try {
    const compra = await kv.get(`compra:${id}`) as Compra;
    if (!compra) {
      return { success: false, error: 'Compra nao encontrada' };
    }

    const fornecedorAntigo = compra.fornecedorId;
    const fornecedorNovo = dados.fornecedorId;
    const pagamentosAssociados = await listarPagamentosAssociadosCompra(compra);
    const totalPagoAssociado = somarPagamentosCompra(pagamentosAssociados);
    const totalGeralAtualizado = Number(dados.totalGeral ?? compra.totalGeral ?? 0);

    if (pagamentosAssociados.length > 0 && fornecedorNovo && fornecedorNovo !== fornecedorAntigo) {
      return { success: false, error: 'Nao e possivel alterar o fornecedor de uma compra com pagamentos associados' };
    }

    if (totalPagoAssociado > totalGeralAtualizado + 0.0001) {
      return { success: false, error: `Esta compra ja possui pagamentos de ${totalPagoAssociado.toFixed(2)} MT, superiores ao novo total do documento` };
    }

    if (fornecedorNovo && fornecedorNovo !== fornecedorAntigo) {
      const comprasFornecedorAntigo = await kv.get(`compras_fornecedor:${fornecedorAntigo}`) || [];
      const novoIndiceFornecedorAntigo = comprasFornecedorAntigo.filter((cId: string) => cId !== id);
      await kv.set(`compras_fornecedor:${fornecedorAntigo}`, novoIndiceFornecedorAntigo);

      const comprasFornecedorNovo = await kv.get(`compras_fornecedor:${fornecedorNovo}`) || [];
      if (!comprasFornecedorNovo.includes(id)) {
        comprasFornecedorNovo.push(id);
        await kv.set(`compras_fornecedor:${fornecedorNovo}`, comprasFornecedorNovo);
      }
    } else {
      const comprasFornecedor = await kv.get(`compras_fornecedor:${compra.fornecedorId}`) || [];
      if (!comprasFornecedor.includes(id)) {
        comprasFornecedor.push(id);
        await kv.set(`compras_fornecedor:${compra.fornecedorId}`, comprasFornecedor);
      }
    }

    const linhasAtualizadas = (dados.linhas || compra.linhas) as LinhaCompra[];
    const compraBaseAtualizada = { ...compra, ...dados, linhas: linhasAtualizadas } as Compra;
    const estadoPagamentoAtualizado = dados.estado || (
      pagamentosAssociados.length > 0
        ? calcularEstadoPagamentoCompra({ ...compraBaseAtualizada, totalGeral: totalGeralAtualizado } as Compra, totalPagoAssociado)
        : compra.estado
    );

    const compraAtualizada: Compra = {
      ...compraBaseAtualizada,
      totalGeral: totalGeralAtualizado,
      estado: estadoPagamentoAtualizado,
      recepcaoStatus: dados.recepcaoStatus || calcularRecepcaoStatus(compraBaseAtualizada),
      id: compra.id,
      empresaId: compra.empresaId,
      dataCriacao: compra.dataCriacao,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`compra:${id}`, compraAtualizada);
    console.log(`[Compras] Compra atualizada: ${compraAtualizada.numeroDocumento}`);
    return { success: true, data: compraAtualizada };
  } catch (error: any) {
    console.error('[Compras] Erro ao atualizar compra:', error);
    return { success: false, error: error.message };
  }
}

export async function deletarCompra(id: string): Promise<{ success: boolean; error?: string }> {
  try {
    const compra = await kv.get(`compra:${id}`) as Compra | null;
    if (!compra) {
      return { success: false, error: 'Compra nao encontrada' };
    }

    const validacaoContabil = await verificarSemLancamentoContabilDefinitivo({
      empresaId: compra.empresaId,
      documentoId: compra.id,
      numeroDocumento: compra.numeroDocumento,
      rotuloDocumento: compra.tipoDocumento || 'Compra',
    });
    if (!validacaoContabil.pode) {
      return { success: false, error: validacaoContabil.motivo };
    }

    const pagamentosAssociados = await listarPagamentosAssociadosCompra(compra);
    const pagamentosManuais = pagamentosAssociados.filter((pagamento) => !pagamentoCompraAutomatico(pagamento));
    if (pagamentosManuais.length > 0) {
      return { success: false, error: 'Nao e possivel eliminar uma compra com pagamentos associados. Remova ou regularize os pagamentos primeiro.' };
    }
    await removerPagamentosAutomaticosCompra(compra);

    const reversao = await reverterEfeitoDocumentoCompra(compra);
    if (!reversao.success) {
      return { success: false, error: reversao.error || 'Falha ao reverter o stock da compra antes de eliminar' };
    }

    const limpezaMovimentos = await limparMovimentosDocumentoSemReverter(
      compra.empresaId,
      compra.numeroDocumento,
      compra.tipoDocumento,
    );
    if (!limpezaMovimentos.success) {
      return { success: false, error: limpezaMovimentos.error || 'Falha ao limpar os movimentos de stock da compra' };
    }

    await removerLancamentosContabeisRascunhoDoDocumento({
      empresaId: compra.empresaId,
      documentoId: compra.id,
      numeroDocumento: compra.numeroDocumento,
    }).catch(() => []);

    const comprasEmpresa = await kv.get(`compras_empresa:${compra.empresaId}`) || [];
    await kv.set(
      `compras_empresa:${compra.empresaId}`,
      comprasEmpresa.filter((compraId: string) => compraId !== id),
    );

    const comprasFornecedor = await kv.get(`compras_fornecedor:${compra.fornecedorId}`) || [];
    await kv.set(
      `compras_fornecedor:${compra.fornecedorId}`,
      comprasFornecedor.filter((compraId: string) => compraId !== id),
    );

    await kv.del(`compra:${id}`);
    return { success: true };
  } catch (error: any) {
    console.error('[Compras] Erro ao deletar compra:', error);
    return { success: false, error: error.message };
  }
}
export async function listarCompras(empresaId: string): Promise<Compra[]> {
  try {
    const comprasIds = await kv.get(`compras_empresa:${empresaId}`) || [];
    const compras: Compra[] = [];

    for (const id of comprasIds) {
      const compra = await kv.get(`compra:${id}`) as Compra;
      if (compra) {
        compras.push(compra);
      }
    }

    return await garantirNumerosInternosCompras(compras);
  } catch (error) {
    console.error('[Compras] Erro ao listar compras:', error);
    return [];
  }
}

export async function listarComprasPorFornecedor(fornecedorId: string): Promise<Compra[]> {
  try {
    const todasCompras = await kv.getByPrefix('compra:');
    const comprasFornecedor = (todasCompras as Compra[]).filter((compra) => compra && compra.fornecedorId === fornecedorId);
    return await garantirNumerosInternosCompras(comprasFornecedor);
  } catch (error) {
    console.error('[Compras] Erro ao listar compras por fornecedor:', error);
    return [];
  }
}

export async function atualizarEstadoCompra(id: string, estado: Compra['estado']): Promise<{ success: boolean; error?: string }> {
  try {
    const compra = await kv.get(`compra:${id}`) as Compra;
    if (!compra) {
      return { success: false, error: 'Compra nao encontrada' };
    }

    if (estado === 'anulado' && compra.estado !== 'anulado') {
      const validacaoContabil = await verificarSemLancamentoContabilDefinitivo({
        empresaId: compra.empresaId,
        documentoId: compra.id,
        numeroDocumento: compra.numeroDocumento,
        rotuloDocumento: compra.tipoDocumento || 'Compra',
      });
      if (!validacaoContabil.pode) {
        return { success: false, error: validacaoContabil.motivo };
      }

      const reversao = await reverterEfeitoDocumentoCompra(compra);
      if (!reversao.success) {
        return { success: false, error: reversao.error || 'Falha ao reverter o stock da compra antes de anular' };
      }

      const limpezaMovimentos = await limparMovimentosDocumentoSemReverter(
        compra.empresaId,
        compra.numeroDocumento,
        compra.tipoDocumento,
      );
      if (!limpezaMovimentos.success) {
        return { success: false, error: limpezaMovimentos.error || 'Falha ao limpar os movimentos de stock da compra' };
      }

      await removerLancamentosContabeisRascunhoDoDocumento({
        empresaId: compra.empresaId,
        documentoId: compra.id,
        numeroDocumento: compra.numeroDocumento,
      }).catch(() => []);
    }

    compra.estado = estado;
    compra.dataAtualizacao = new Date().toISOString();

    await kv.set(`compra:${id}`, compra);
    return { success: true };
  } catch (error: any) {
    console.error('[Compras] Erro ao atualizar estado:', error);
    return { success: false, error: error.message };
  }
}

export async function recepcionarCompra(
  id: string,
  dados: {
    armazemId?: string;
    dataRecepcao?: string;
    recebidoPor?: string;
    linhas: Array<{
      linhaId: string;
      quantidade: number;
      lote?: string;
      dataValidade?: string;
      dataFabricacao?: string;
      armazemId?: string;
    }>;
  }
): Promise<{ success: boolean; data?: Compra; error?: string }> {
  const movimentosCriados: string[] = [];
  const reverterMovimentosRecepcao = async () => {
    for (const movimentoId of [...movimentosCriados].reverse()) {
      const reversao = await movimentosStock.deletarMovimento(movimentoId);
      if (!reversao.success) {
        console.error('[Compras] Erro ao reverter movimento de recepcao apos falha:', movimentoId, reversao.error);
      }
    }
  };

  try {
    const compra = await buscarCompraPorId(id);
    if (!compra) {
      return { success: false, error: 'Compra nao encontrada' };
    }

    const perfilDocumento = obterPerfilDocumentoCompra(compra.tipoDocumento);
    if (!perfilDocumento.movimentaStock || perfilDocumento.efeitoStock !== 'entrada') {
      return { success: false, error: 'Este tipo de documento nao permite recepcao de stock' };
    }

    if (!dados.linhas || dados.linhas.length === 0) {
      return { success: false, error: 'Informe pelo menos uma linha para recepcionar' };
    }

    const dataRecepcao = dados.dataRecepcao || new Date().toISOString().split('T')[0];
    const recebidoEm = new Date().toISOString();
    const linhasAtualizadas = [...compra.linhas];
    const totaisSolicitadosPorLinha = new Map<string, number>();
    for (const linhaRecepcao of dados.linhas) {
      const quantidade = Number(linhaRecepcao.quantidade || 0);
      if (!linhaRecepcao.linhaId) {
        return { success: false, error: 'Linha de recepcao sem identificador' };
      }
      if (!Number.isFinite(quantidade) || quantidade <= 0) {
        return { success: false, error: `Quantidade invalida para a linha ${linhaRecepcao.linhaId}` };
      }
      totaisSolicitadosPorLinha.set(
        linhaRecepcao.linhaId,
        (totaisSolicitadosPorLinha.get(linhaRecepcao.linhaId) || 0) + quantidade,
      );
    }

    for (const [linhaId, quantidadeTotalSolicitada] of totaisSolicitadosPorLinha.entries()) {
      const linha = compra.linhas.find((item) => item.id === linhaId);
      if (!linha) {
        return { success: false, error: `Linha ${linhaId} nao encontrada na compra` };
      }
      if (!linha.artigoId) {
        return { success: false, error: `A linha ${linha.codigo} nao esta ligada a um artigo` };
      }

      const artigo = await artigos.buscarArtigoPorId(linha.artigoId);
      if (!artigo) {
        return { success: false, error: `Artigo ${linha.codigo} nao encontrado` };
      }
      if (artigo.tipo === 'servico' || linha.tipoArtigo === 'servico') {
        return { success: false, error: `O artigo ${linha.codigo} e um servico e nao pode entrar em stock` };
      }

      const quantidadePendente = linha.quantidade - obterQuantidadeRecebidaLinha(linha);
      if (quantidadeTotalSolicitada > quantidadePendente) {
        return { success: false, error: `A linha ${linha.codigo} tem apenas ${quantidadePendente} unidade(s) pendente(s)` };
      }
    }

    for (const linhaRecepcao of dados.linhas) {
      const linha = compra.linhas.find((item) => item.id === linhaRecepcao.linhaId);
      if (!linha || !linha.artigoId) continue;

      const artigo = await artigos.buscarArtigoPorId(linha.artigoId);
      if (!artigo) continue;

      const armazemId = linhaRecepcao.armazemId || dados.armazemId || compra.armazemId || linha.armazemId || artigo.armazemId;
      if (!armazemId) {
        return { success: false, error: `Defina um armazem para recepcionar a linha ${linha.codigo}` };
      }

      const armazem = await buscarArmazemPorId(armazemId);
      if (!armazem || !armazem.ativo) {
        return { success: false, error: `Armazem invalido para a linha ${linha.codigo}` };
      }
    }
    for (const linhaRecepcao of dados.linhas) {
      const linhaIndex = linhasAtualizadas.findIndex((linha) => linha.id === linhaRecepcao.linhaId);
      if (linhaIndex < 0) {
        return { success: false, error: `Linha ${linhaRecepcao.linhaId} nao encontrada na compra` };
      }

      const linha = linhasAtualizadas[linhaIndex];
      const quantidadeRecepcao = Number(linhaRecepcao.quantidade || 0);
      if (!linha.artigoId) {
        return { success: false, error: `A linha ${linha.codigo} nao esta ligada a um artigo` };
      }

      if (!Number.isFinite(quantidadeRecepcao) || quantidadeRecepcao <= 0) {
        return { success: false, error: `Quantidade invalida para a linha ${linha.codigo}` };
      }

      const artigo = await artigos.buscarArtigoPorId(linha.artigoId);
      if (!artigo) {
        return { success: false, error: `Artigo ${linha.codigo} nao encontrado` };
      }

      if (artigo.tipo === 'servico' || linha.tipoArtigo === 'servico') {
        return { success: false, error: `O artigo ${linha.codigo} e um servico e nao pode entrar em stock` };
      }

      const quantidadeRecebida = obterQuantidadeRecebidaLinha(linha);
      const quantidadePendente = linha.quantidade - quantidadeRecebida;
      if (quantidadeRecepcao > quantidadePendente) {
        return { success: false, error: `A linha ${linha.codigo} tem apenas ${quantidadePendente} unidade(s) pendente(s)` };
      }

      const armazemId = linhaRecepcao.armazemId || dados.armazemId || compra.armazemId || linha.armazemId || artigo.armazemId;
      if (!armazemId) {
        return { success: false, error: `Defina um armazem para recepcionar a linha ${linha.codigo}` };
      }

      const armazem = await buscarArmazemPorId(armazemId);
      if (!armazem || !armazem.ativo) {
        return { success: false, error: `Armazem invalido para a linha ${linha.codigo}` };
      }

      const resultadoMovimento = await movimentosStock.criarMovimento({
        empresaId: compra.empresaId,
        artigoId: linha.artigoId,
        tipo: 'entrada',
        quantidade: quantidadeRecepcao,
        motivo: 'recepcao',
        armazemId,
        lote: linhaRecepcao.lote || linha.lote,
        custoUnitario: linha.precoUnitario,
        documentoTipo: `Compra ${compra.tipoDocumento}`,
        documentoNumero: compra.numeroDocumento,
        observacoes: `Recepcao de compra ${compra.numeroDocumento}`,
        responsavel: dados.recebidoPor,
        dataMovimento: dataRecepcao,
      });

      if (!resultadoMovimento.success || !resultadoMovimento.data) {
        await reverterMovimentosRecepcao();
        return { success: false, error: resultadoMovimento.error || `Falha ao movimentar stock da linha ${linha.codigo}` };
      }
      const loteExistente = await stockLotes.buscarLotePorIdentidade(
        compra.empresaId,
        linha.artigoId,
        armazemId,
        linhaRecepcao.lote || linha.lote,
        linhaRecepcao.dataValidade || linha.dataValidade,
      );

      try {
        await stockLotes.upsertLote({
          empresaId: compra.empresaId,
          artigoId: linha.artigoId,
          armazemId,
          lote: linhaRecepcao.lote || linha.lote,
          dataValidade: linhaRecepcao.dataValidade || linha.dataValidade,
          dataFabricacao: linhaRecepcao.dataFabricacao || linha.dataFabricacao,
          quantidade: (loteExistente?.quantidade || 0) + quantidadeRecepcao,
          quantidadeReservada: loteExistente?.quantidadeReservada || 0,
          custoUnitario: linha.precoUnitario,
          fornecedorId: compra.fornecedorId,
          documentoCompraId: compra.id,
        });
      } catch (error: any) {
        await reverterMovimentoEntradaCompraSemLote(resultadoMovimento.data);
        await reverterMovimentosRecepcao();
        return { success: false, error: `Falha ao atualizar lote da linha ${linha.codigo}: ${error.message || error}` };
      }
      movimentosCriados.push(resultadoMovimento.data.id);

      const recepcao: RecepcaoLinhaCompra = {
        id: `recepcao_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        linhaId: linha.id,
        quantidade: quantidadeRecepcao,
        lote: linhaRecepcao.lote || linha.lote,
        dataValidade: linhaRecepcao.dataValidade || linha.dataValidade,
        dataFabricacao: linhaRecepcao.dataFabricacao || linha.dataFabricacao,
        armazemId,
        recebidoEm,
        recebidoPor: dados.recebidoPor,
      };

      linhasAtualizadas[linhaIndex] = {
        ...linha,
        lote: recepcao.lote || linha.lote,
        dataValidade: recepcao.dataValidade || linha.dataValidade,
        dataFabricacao: recepcao.dataFabricacao || linha.dataFabricacao,
        quantidadeRecebida: quantidadeRecebida + quantidadeRecepcao,
        recepcoes: [...(linha.recepcoes || []), recepcao],
      };
    }

    const compraAtualizada: Compra = {
      ...compra,
      armazemId: dados.armazemId || compra.armazemId,
      linhas: linhasAtualizadas,
      recepcaoStatus: calcularRecepcaoStatus({ ...compra, linhas: linhasAtualizadas } as Compra),
      recepcionadoEm: recebidoEm,
      recepcionadoPor: dados.recebidoPor || compra.recepcionadoPor,
      dataAtualizacao: recebidoEm,
    };

    await kv.set(`compra:${id}`, compraAtualizada);
    return { success: true, data: compraAtualizada };
  } catch (error: any) {
    console.error('[Compras] Erro ao recepcionar compra:', error);
    if (movimentosCriados.length > 0) {
      await reverterMovimentosRecepcao();
    }
    return { success: false, error: error.message };
  }
}

export async function criarPagamentoCompra(dados: Omit<PagamentoCompra, 'id' | 'dataCriacao'>): Promise<{ success: boolean; data?: PagamentoCompra; error?: string }> {
  try {
    const valor = Number(dados.valor || 0);
    if (!dados.empresaId || !dados.fornecedorId || !Number.isFinite(valor) || valor <= 0) {
      return { success: false, error: 'Empresa, fornecedor e valor maior que zero sao obrigatorios' };
    }

    let compraAssociada: Compra | null = null;
    let totalPagoAnterior = 0;

    if (dados.compraId) {
      compraAssociada = await kv.get(`compra:${dados.compraId}`) as Compra | null;
      if (!compraAssociada) return { success: false, error: 'Compra associada nao encontrada' };
      if (compraAssociada.empresaId !== dados.empresaId) return { success: false, error: 'A compra associada pertence a outra empresa' };
      if (compraAssociada.fornecedorId !== dados.fornecedorId) return { success: false, error: 'O fornecedor do pagamento nao corresponde ao fornecedor da compra' };
      if (compraAssociada.estado === 'anulado') return { success: false, error: 'Nao e possivel pagar uma compra anulada' };

      const pagamentosCompra = await listarPagamentosAssociadosCompra(compraAssociada);
      totalPagoAnterior = somarPagamentosCompra(pagamentosCompra);
      const totalDepoisPagamento = totalPagoAnterior + valor;
      if (totalDepoisPagamento > Number(compraAssociada.totalGeral || 0) + 0.0001) {
        const saldo = Math.max(0, Number(compraAssociada.totalGeral || 0) - totalPagoAnterior);
        return { success: false, error: `Pagamento superior ao saldo pendente da compra. Saldo disponivel: ${saldo.toFixed(2)} MT` };
      }
    }

    const pagamentosExistentes = await listarPagamentosCompra(dados.empresaId);
    validarDataEmissaoCronologica({ ...dados, valor }, pagamentosExistentes, {
      rotuloDocumento: 'Pagamento a Fornecedor',
    });

    const id = `pagamento_compra_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    // ✅ ...dados vem ANTES de id: mesmo bug e correcao de clientes.tsx/
    // fornecedores.tsx/compras.tsx (criarCompra) — um id vindo no corpo do
    // pedido nao pode sobrepor-se ao id gerado aqui no servidor.
    const pagamento: PagamentoCompra = {
      ...dados,
      id,
      valor,
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`pagamento_compra:${id}`, pagamento);

    const pagamentosEmpresa = await kv.get(`pagamentos_compra_empresa:${dados.empresaId}`) || [];
    if (!pagamentosEmpresa.includes(id)) {
      pagamentosEmpresa.push(id);
      await kv.set(`pagamentos_compra_empresa:${dados.empresaId}`, pagamentosEmpresa);
    }

    const pagamentosFornecedor = await kv.get(`pagamentos_compra_fornecedor:${dados.fornecedorId}`) || [];
    if (!pagamentosFornecedor.includes(id)) {
      pagamentosFornecedor.push(id);
      await kv.set(`pagamentos_compra_fornecedor:${dados.fornecedorId}`, pagamentosFornecedor);
    }

    if (compraAssociada && dados.compraId) {
      const totalPago = totalPagoAnterior + valor;
      await atualizarEstadoCompra(dados.compraId, calcularEstadoPagamentoCompra(compraAssociada, totalPago));
    }

    console.log(`[Compras] Pagamento criado: ${dados.numeroDocumento} - ${valor} MT`);
    return { success: true, data: pagamento };
  } catch (error: any) {
    console.error('[Compras] Erro ao criar pagamento:', error);
    return { success: false, error: error.message };
  }
}
export async function listarPagamentosCompra(empresaId: string): Promise<PagamentoCompra[]> {
  try {
    const pagamentosIds = await kv.get(`pagamentos_compra_empresa:${empresaId}`) || [];
    const pagamentos: PagamentoCompra[] = [];

    for (const id of pagamentosIds) {
      const pagamento = await kv.get(`pagamento_compra:${id}`) as PagamentoCompra;
      if (pagamento) {
        pagamentos.push(pagamento);
      }
    }

    return pagamentos;
  } catch (error) {
    console.error('[Compras] Erro ao listar pagamentos:', error);
    return [];
  }
}

export async function listarPagamentosPorFornecedor(fornecedorId: string): Promise<PagamentoCompra[]> {
  try {
    const pagamentosIds = await kv.get(`pagamentos_compra_fornecedor:${fornecedorId}`) || [];
    const pagamentos: PagamentoCompra[] = [];

    for (const id of pagamentosIds) {
      const pagamento = await kv.get(`pagamento_compra:${id}`) as PagamentoCompra;
      if (pagamento) {
        pagamentos.push(pagamento);
      }
    }

    return pagamentos;
  } catch (error) {
    console.error('[Compras] Erro ao listar pagamentos por fornecedor:', error);
    return [];
  }
}

// ✅ Um PagamentoCompra sem compraId e um adiantamento a fornecedor (ver
// contabilizarPagamentoFornecedor em index.tsx, que so o classifica como
// 'adiantamento_fornecedor' quando nao ha compraId). Nao existe ainda
// nenhum mecanismo que ligue esse adiantamento a uma compra futura, por
// isso o saldo fica sempre "por aplicar" ate ser reconciliado manualmente.
export async function obterSaldoAdiantamentosFornecedor(fornecedorId: string): Promise<number> {
  const pagamentos = await listarPagamentosPorFornecedor(fornecedorId);
  return pagamentos
    .filter((pagamento) => !pagamento.compraId)
    .reduce((total, pagamento) => total + Number(pagamento.valor || 0), 0);
}

export async function listarPagamentosPorCompra(compraId: string): Promise<PagamentoCompra[]> {
  try {
    const compra = await kv.get(`compra:${compraId}`) as Compra;
    if (!compra) return [];

    return await listarPagamentosAssociadosCompra(compra);
  } catch (error) {
    console.error('[Compras] Erro ao listar pagamentos por compra:', error);
    return [];
  }
}
