import * as kv from "./kv_store.tsx";
import { buscarArtigoPorId, atualizarEstoque } from "./artigos.tsx";
import { buscarArmazemPorId } from "./armazens.tsx";
import * as stockArmazem from "./stock-armazem.tsx";
import * as stockLotes from "./stock-lotes.tsx";
import { createLogger } from "./logger.tsx";
import { verificarSemLancamentoContabilDefinitivo } from "./integridade-documentos.tsx";

const logger = createLogger('MovimentosStock');

// ========== PREFIXO ÚNICO PARA MOVIMENTOS DE STOCK ==========
const MOVIMENTOS_STOCK_PREFIX = "movimento_stock:";

// ========== TIPOS ==========

export type TipoMovimento = "entrada" | "saida";

// Motivos de ENTRADA
export type MotivoEntrada = 
  | "recepcao"           // Produto recebido (compra/fornecedor) - AUTOMÁTICO
  | "devolucao_cliente"  // Produto devolvido por cliente - AUTOMÁTICO
  | "ajuste_positivo";   // Ajuste positivo de stock - MANUAL

// Motivos de SAÍDA
export type MotivoSaida = 
  | "venda"              // Produto vendido - AUTOMÁTICO
  | "devolucao_fornecedor" // Produto devolvido ao fornecedor - AUTOMÁTICO
  | "ajuste_negativo"    // Ajuste negativo de stock - MANUAL
  | "consumo_interno"    // Produto consumido internamente - MANUAL
  | "danificacao"        // Produto danificado/perdido - MANUAL
  | "perda_vencimento";  // Produto perdido por validade/expiração - MANUAL

export type MotivoMovimento = MotivoEntrada | MotivoSaida;

// Motivos MANUAIS (apenas estes aparecem no formulário)
export const motivosEntradaManuais: MotivoEntrada[] = ["ajuste_positivo"];
export const motivosSaidaManuais: MotivoSaida[] = ["consumo_interno", "danificacao", "perda_vencimento", "ajuste_negativo"];

// Motivos AUTOMÁTICOS (criados por outros módulos)
export const motivosEntradaAutomaticos: MotivoEntrada[] = ["recepcao", "devolucao_cliente"];
export const motivosSaidaAutomaticos: MotivoSaida[] = ["venda", "devolucao_fornecedor"];

function normalizarTipoMovimento(valor: unknown): TipoMovimento | null {
  const tipo = String(valor || "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .trim()
    .toLowerCase();

  if (tipo === "entrada") return "entrada";
  if (tipo === "saida") return "saida";
  return null;
}

function arredondarMoedaMovimento(valor: number): number {
  return Math.round(((Number(valor) || 0) + Number.EPSILON) * 100) / 100;
}

function obterNumeroPositivoMovimento(...valores: unknown[]): number | undefined {
  for (const valor of valores) {
    const numero = Number(valor);
    if (Number.isFinite(numero) && numero > 0) {
      return numero;
    }
  }

  return undefined;
}

function normalizarMetodoCusteioMovimento(valor?: string): stockLotes.MetodoCusteioStock {
  const metodo = (valor || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_+|_+$/g, '');

  if (metodo === 'fifo') return 'fifo';
  if (metodo === 'fefo') return 'fefo';
  if (metodo === 'lifo') return 'lifo';
  if (metodo === 'manual') return 'manual';
  return 'custo_medio';
}

async function calcularCustoUnitarioMovimento(
  dados: Partial<MovimentoStock> & { quantidade: number },
  artigo: any,
  planoFEFO: stockLotes.PlanoConsumoLote[],
  metodoCusteio: stockLotes.MetodoCusteioStock,
): Promise<number> {
  const custoInformado = obterNumeroPositivoMovimento(
    (dados as any).custoUnitario,
    (dados as any).precoUnitario,
    (dados as any).valorUnitario,
  );

  if (custoInformado !== undefined) {
    return arredondarMoedaMovimento(custoInformado);
  }

  // Custo medio ponderado real, mantido por armazem em stock-armazem.tsx
  // (atualizarStockArmazem actualiza-o a cada entrada). artigo.custoMedio nao
  // existe no tipo Artigo — so precoCompra (ultimo preco de compra) e mantido
  // ai — por isso este e sempre o primeiro fallback antes de cair para o
  // ultimo preco de compra.
  let custoMedioArmazem: number | undefined;
  if (metodoCusteio === 'custo_medio' && dados.armazemId && dados.empresaId && dados.artigoId) {
    const stockDoArmazem = await stockArmazem.buscarStockArtigoArmazem(
      dados.empresaId,
      dados.artigoId,
      dados.armazemId,
    );
    custoMedioArmazem = obterNumeroPositivoMovimento(stockDoArmazem?.custoMedio);
  }

  if (metodoCusteio === 'custo_medio') {
    return arredondarMoedaMovimento(
      obterNumeroPositivoMovimento(
        custoMedioArmazem,
        artigo?.custoMedio,
        artigo?.precoCompra,
        artigo?.precoCusto,
        artigo?.valorCusto,
      ) || 0,
    );
  }

  if (planoFEFO.length > 0) {
    let custoTotal = 0;
    let quantidadeTotal = 0;

    for (const plano of planoFEFO) {
      const lote = await stockLotes.buscarLotePorId(plano.loteId);
      const custoLote = obterNumeroPositivoMovimento(lote?.custoUnitario) || 0;
      if (custoLote > 0 && plano.quantidade > 0) {
        custoTotal += custoLote * plano.quantidade;
        quantidadeTotal += plano.quantidade;
      }
    }

    if (custoTotal > 0 && quantidadeTotal > 0) {
      return arredondarMoedaMovimento(custoTotal / quantidadeTotal);
    }
  }

  return arredondarMoedaMovimento(
    obterNumeroPositivoMovimento(
      custoMedioArmazem,
      artigo?.custoMedio,
      artigo?.precoCompra,
      artigo?.precoCusto,
      artigo?.valorCusto,
    ) || 0,
  );
}
function normalizarMotivoMovimento(
  motivo: string | undefined,
  tipo: TipoMovimento,
): MotivoMovimento | null {
  if (!motivo) {
    return tipo === "entrada" ? "ajuste_positivo" : "ajuste_negativo";
  }

  const motivoNormalizado = motivo.trim().toLowerCase();

  const mapaLegado: Record<string, MotivoMovimento> = {
    devolucao_interna: "ajuste_positivo",
    transferencia_entrada: "ajuste_positivo",
    acerto_estoque: "ajuste_positivo",
    transferencia_saida: "ajuste_negativo",
    perda_avaria: "danificacao",
  };

  const motivoCanonico = (mapaLegado[motivoNormalizado] || motivoNormalizado) as MotivoMovimento;

  const motivosValidosEntrada = new Set<MotivoEntrada>([
    "recepcao",
    "devolucao_cliente",
    "ajuste_positivo",
  ]);

  const motivosValidosSaida = new Set<MotivoSaida>([
    "venda",
    "devolucao_fornecedor",
    "ajuste_negativo",
    "consumo_interno",
    "danificacao",
    "perda_vencimento",
  ]);

  if (tipo === "entrada" && motivosValidosEntrada.has(motivoCanonico as MotivoEntrada)) {
    return motivoCanonico as MotivoEntrada;
  }

  if (tipo === "saida" && motivosValidosSaida.has(motivoCanonico as MotivoSaida)) {
    return motivoCanonico as MotivoSaida;
  }

  return null;
}

export interface MovimentoStock {
  id: string;
  empresaId: string;
  artigoId: string;
  lote?: string;
  loteId?: string;
  artigoCodigo: string; // Desnormalizado
  artigoNome: string; // Desnormalizado
  tipo: TipoMovimento; // entrada ou saída
  quantidade: number;
  custoUnitario?: number;
  valorTotal?: number;
  metodoCusteio?: stockLotes.MetodoCusteioStock;
  motivo: MotivoMovimento;
  documentoId?: string;
  documentoTipo?: string; // Ex: "Factura", "Nota de Crédito", etc
  documentoNumero?: string; // Número do documento relacionado
  armazemId?: string; // ID do armazém onde o movimento ocorre
  armazemCodigo?: string; // Código do armazém (desnormalizado)
  armazemNome?: string; // Nome do armazém (desnormalizado)
  armazemOrigem?: string; // Para transferências
  armazemDestino?: string; // Para transferências
  observacoes?: string;
  responsavel?: string; // Quem registrou o movimento
  responsavelId?: string;
  responsavelNome?: string;
  responsavelEmail?: string;
  criadoPor?: string;
  criadoPorNome?: string;
  criadoPorEmail?: string;
  lotesConsumidos?: Array<{
    loteId: string;
    lote?: string;
    dataValidade?: string;
    quantidade: number;
  }>;
  movimentoOriginalId?: string;
  movimentoReversaoId?: string;
  revertidoEm?: string;
  dataCriacao: string;
  dataMovimento: string; // Data efetiva do movimento
}

// ========== FUNÇÕES DE GESTÃO DE MOVIMENTOS ==========

/**
 * Criar novo movimento de stock
 */
export async function criarMovimento(
  dados: Partial<MovimentoStock> & { 
    empresaId: string; 
    artigoId: string;
    tipo: TipoMovimento;
    quantidade: number;
    permitirConsumoExpirados?: boolean;
  }
): Promise<{ success: boolean; data?: MovimentoStock; error?: string; warning?: string }> {
  try {
    logger.info('[MovimentosStock] 🔵 DADOS RECEBIDOS:', JSON.stringify(dados, null, 2));
    
    // Validar dados obrigatórios
    const tipoNormalizado = normalizarTipoMovimento(dados.tipo);
    const quantidadeNormalizada = Number(dados.quantidade);
    const camposFaltando = [
      !dados.empresaId ? "empresaId" : "",
      !dados.artigoId ? "artigoId" : "",
      !dados.tipo ? "tipo" : "",
      dados.quantidade === undefined || dados.quantidade === null || dados.quantidade === "" ? "quantidade" : "",
    ].filter(Boolean);

    if (camposFaltando.length > 0) {
      return { success: false, error: `Dados obrigatorios faltando: ${camposFaltando.join(", ")}` };
    }

    if (!tipoNormalizado) {
      return { success: false, error: "Tipo de movimento invalido. Use entrada ou saida." };
    }

    if (!Number.isFinite(quantidadeNormalizada) || quantidadeNormalizada <= 0) {
      return { success: false, error: "Quantidade deve ser maior que zero" };
    }

    dados.tipo = tipoNormalizado;
    dados.quantidade = quantidadeNormalizada;

    if (!dados.empresaId || !dados.artigoId || !dados.tipo || !dados.quantidade) {
      return { success: false, error: "Dados obrigatórios faltando" };
    }

    if (dados.quantidade <= 0) {
      return { success: false, error: "Quantidade deve ser maior que zero" };
    }

    const motivoNormalizado = normalizarMotivoMovimento(dados.motivo, dados.tipo);
    if (!motivoNormalizado) {
      return { success: false, error: "Motivo de movimento inválido para o tipo selecionado" };
    }

    // Buscar artigo para validar e obter dados
    const artigo = await buscarArtigoPorId(dados.artigoId);
    if (!artigo) {
      return { success: false, error: "Artigo não encontrado" };
    }

    // Validar se é produto (serviços não têm estoque)
    if (artigo.tipo === "servico") {
      return { success: false, error: "Serviços não possuem estoque" };
    }

    const metodoCusteio = normalizarMetodoCusteioMovimento(
      (dados as any).metodoCusteio || artigo.metodoCusteio || artigo.metodoCusto,
    );

    // Gerar ID
    const id = `movimento_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const dataAtual = new Date().toISOString();
    
    // Se armazemId fornecido, buscar dados do armazém
    let armazem = null;
    if (dados.armazemId) {
      armazem = await buscarArmazemPorId(dados.armazemId, dados.empresaId);
      if (!armazem) {
        return { success: false, error: "Armazém não encontrado" };
      }
      if (!armazem.ativo) {
        return { success: false, error: "Armazém está inativo" };
      }
    }

    if (dados.tipo === "saida") {
      if (armazem) {
        const stockAtualArmazem = await stockArmazem.buscarStockArtigoArmazem(dados.empresaId, dados.artigoId, armazem.id);
        const stockDisponivel = stockAtualArmazem?.quantidadeDisponivel ?? (artigo.estoqueAtual || 0);

        if (stockDisponivel < dados.quantidade) {
          return {
            success: false,
            error: `Stock insuficiente no armazém ${armazem.nome}. Disponível: ${stockDisponivel}, solicitado: ${dados.quantidade}`,
          };
        }
      } else {
        const stockDisponivel = artigo.estoqueAtual || 0;
        if (stockDisponivel < dados.quantidade) {
          return {
            success: false,
            error: `Stock insuficiente para o artigo ${artigo.codigo}. Disponível: ${stockDisponivel}, solicitado: ${dados.quantidade}`,
          };
        }
      }
    }

    // ✅ Avisa (sem bloquear) quando este movimento acontece num armazem que
    // tem uma contagem fisica em curso — as diferencas dessa contagem sao
    // calculadas contra o stock de sistema no momento da finalizacao, por
    // isso um movimento "normal" (venda/compra) no meio da contagem pode ser
    // mal-interpretado como diferenca fisica real. Exclui os movimentos que
    // a propria finalizacao do inventario gera (senao a contagem avisava-se
    // sempre a ela propria).
    let avisoContagemFisicaEmCurso: string | undefined;
    if (armazem && dados.documentoTipo !== 'Inventario Fisico') {
      const inventariosArmazem = await kv.getByPrefix<any>(`inventario:${dados.empresaId}:`);
      const inventarioEmContagem = inventariosArmazem.find(
        (inv: any) => inv?.status === 'em_contagem' && inv?.armazemId === armazem!.id,
      );
      if (inventarioEmContagem) {
        avisoContagemFisicaEmCurso = `Atencao: o armazem ${armazem.nome} tem a contagem fisica ${inventarioEmContagem.numero} em curso. Este movimento pode ser interpretado como diferenca fisica ao finalizar essa contagem.`;
      }
    }

    let planoFEFO: stockLotes.PlanoConsumoLote[] = [];
    if (dados.tipo === "saida") {
      if (dados.loteId) {
        const planoLoteResultado = await stockLotes.planearConsumoLoteEspecifico(
          dados.empresaId,
          dados.artigoId,
          dados.loteId,
          dados.quantidade,
          armazem?.id,
        );

        if (!planoLoteResultado.success || !planoLoteResultado.plano) {
          return {
            success: false,
            error: planoLoteResultado.error,
          };
        }

        planoFEFO = [planoLoteResultado.plano];
      } else {
        const planoResultado = await stockLotes.planearConsumoPorLotes(
          dados.empresaId,
          dados.artigoId,
          dados.quantidade,
          armazem?.id,
          {
            incluirExpirados: dados.permitirConsumoExpirados ?? false,
            metodoCusteio,
          },
        );

        if (!planoResultado.success) {
          return {
            success: false,
            error: planoResultado.error,
          };
        }

        if (planoResultado.temLotes) {
          planoFEFO = planoResultado.plano;
        }
      }
    }
    
    const lotesRastreados = planoFEFO.length > 0
      ? planoFEFO.map((item) => ({
          loteId: item.loteId,
          lote: item.lote,
          dataValidade: item.dataValidade,
          quantidade: item.quantidade,
        }))
      : (dados.lotesConsumidos && dados.lotesConsumidos.length > 0
          ? dados.lotesConsumidos.map((item) => ({
              loteId: item.loteId,
              lote: item.lote,
              dataValidade: item.dataValidade,
              quantidade: item.quantidade,
            }))
          : undefined);

    const custoUnitario = await calcularCustoUnitarioMovimento(dados, artigo, planoFEFO, metodoCusteio);
    const valorTotal = arredondarMoedaMovimento(custoUnitario * dados.quantidade);

    const movimento: MovimentoStock = {
      id,
      empresaId: dados.empresaId,
      artigoId: dados.artigoId,
      lote: dados.lote?.trim() || undefined,
      loteId: dados.loteId,
      artigoCodigo: artigo.codigo,
      artigoNome: artigo.nome || artigo.codigo,
      tipo: dados.tipo,
      quantidade: dados.quantidade,
      custoUnitario,
      valorTotal,
      metodoCusteio,
      motivo: motivoNormalizado,
      documentoId: (dados as any).documentoId,
      documentoTipo: dados.documentoTipo,
      documentoNumero: dados.documentoNumero,
      armazemId: armazem?.id,
      armazemCodigo: armazem?.codigo,
      armazemNome: armazem?.nome,
      armazemOrigem: dados.armazemOrigem,
      armazemDestino: dados.armazemDestino,
      observacoes: dados.observacoes,
      responsavel: dados.responsavel || (dados as any).responsavelNome || (dados as any).criadoPorNome,
      responsavelId: (dados as any).responsavelId || (dados as any).usuarioAuditoriaId || (dados as any).criadoPor,
      responsavelNome: (dados as any).responsavelNome || dados.responsavel || (dados as any).usuarioAuditoriaNome || (dados as any).criadoPorNome,
      responsavelEmail: (dados as any).responsavelEmail || (dados as any).usuarioAuditoriaEmail || (dados as any).criadoPorEmail,
      criadoPor: (dados as any).criadoPor || (dados as any).usuarioAuditoriaId,
      criadoPorNome: (dados as any).criadoPorNome || (dados as any).usuarioAuditoriaNome || dados.responsavel,
      criadoPorEmail: (dados as any).criadoPorEmail || (dados as any).usuarioAuditoriaEmail,
      lotesConsumidos: lotesRastreados,
      dataCriacao: dataAtual,
      dataMovimento: dados.dataMovimento || dataAtual.split('T')[0],
    };

    // Atualizar estoque do artigo (estoque geral)
    const operacao = dados.tipo === "entrada" ? "adicionar" : "remover";
    const resultadoEstoque = await atualizarEstoque(
      dados.artigoId,
      dados.quantidade,
      operacao
    );

    if (!resultadoEstoque.success) {
      return { 
        success: false, 
        error: `Erro ao atualizar estoque: ${resultadoEstoque.error}` 
      };
    }

    // Se armazém fornecido, atualizar stock por armazém
    if (armazem) {
      const quantidadeDelta = dados.tipo === "entrada" ? dados.quantidade : -dados.quantidade;
      
      // console.log('[MovimentosStock] 📦 TENTANDO ATUALIZAR STOCK-ARMAZEM:', {
      //   empresaId: dados.empresaId,
      //   armazemId: armazem.id,
      //   artigoId: dados.artigoId,
      //   quantidadeDelta,
      //   tipo: dados.tipo
      // });
      
      // ✅ CRÍTICO: Usar atualizarStockArmazem para criar/atualizar stock no armazém
      const resultadoStockArmazem = await stockArmazem.atualizarStockArmazem({
        empresaId: dados.empresaId,
        armazemId: armazem.id,
        armazemCodigo: armazem.codigo,
        armazemNome: armazem.nome,
        artigoId: dados.artigoId,
        artigoCodigo: artigo.codigo,
        artigoNome: artigo.nome,
        quantidadeDelta,
        custoUnitarioEntrada: dados.tipo === "entrada" ? custoUnitario : undefined,
      });

      // console.log('[MovimentosStock] 📦 RESULTADO STOCK-ARMAZEM:', resultadoStockArmazem);

      if (!resultadoStockArmazem.success) {
        // Reverter o estoque geral se falhar
        const operacaoReversa = dados.tipo === "entrada" ? "remover" : "adicionar";
        await atualizarEstoque(dados.artigoId, dados.quantidade, operacaoReversa);
        return { 
          success: false, 
          error: `Erro ao atualizar stock do armazém: ${resultadoStockArmazem.error}` 
        };
      }
      
      // ✅ OBTER STOCK TOTAL DO ARTIGO após atualizar armazém
      const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(dados.empresaId, dados.artigoId);
      // console.log(`[MovimentosStock] 🔄 Stock total obtido: ${stockTotalRecalculado}`);
      
      // Atualizar o estoqueAtual do artigo com o valor recalculado
      await atualizarEstoque(dados.artigoId, stockTotalRecalculado, 'definir');
    }

    if (planoFEFO.length > 0) {
      const resultadoConsumoFEFO = await stockLotes.aplicarPlanoConsumoFEFO(planoFEFO);

      if (!resultadoConsumoFEFO.success) {
        if (armazem) {
          await stockArmazem.atualizarStockArmazem({
            empresaId: dados.empresaId,
            armazemId: armazem.id,
            armazemCodigo: armazem.codigo,
            armazemNome: armazem.nome,
            artigoId: dados.artigoId,
            artigoCodigo: artigo.codigo,
            artigoNome: artigo.nome,
            quantidadeDelta: -(dados.tipo === "entrada" ? dados.quantidade : -dados.quantidade),
          });

          const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(dados.empresaId, dados.artigoId);
          await atualizarEstoque(dados.artigoId, stockTotalRecalculado, 'definir');
        } else {
          const operacaoReversa = dados.tipo === "entrada" ? "remover" : "adicionar";
          await atualizarEstoque(dados.artigoId, dados.quantidade, operacaoReversa);
        }

        return {
          success: false,
          error: `Erro ao consumir lotes FEFO: ${resultadoConsumoFEFO.error}`,
        };
      }
    }

    // Salvar movimento
    await kv.set(`${MOVIMENTOS_STOCK_PREFIX}${id}`, movimento);

    // console.log(`[MovimentosStock] ✅ Movimento criado: ${movimento.tipo} - ${movimento.artigoCodigo}${armazem ? ` no armazém ${armazem.codigo}` : ''}`);

    return { success: true, data: movimento, warning: avisoContagemFisicaEmCurso };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao criar movimento:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Buscar movimento por ID
 */
export async function buscarMovimentoPorId(id: string): Promise<MovimentoStock | null> {
  try {
    const movimento = await kv.get(`${MOVIMENTOS_STOCK_PREFIX}${id}`);
    return movimento as MovimentoStock | null;
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao buscar movimento:", error);
    return null;
  }
}

/**
 * Listar movimentos de uma empresa
 */
export async function listarMovimentos(
  empresaId: string,
  filtros?: {
    tipo?: TipoMovimento;
    artigoId?: string;
    dataInicio?: string;
    dataFim?: string;
    motivo?: MotivoMovimento;
    documentoTipo?: string;
    documentoNumero?: string;
    documentoId?: string;
  }
): Promise<MovimentoStock[]> {
  try {
    const todosMovimentos = await kv.getByPrefix<MovimentoStock>(MOVIMENTOS_STOCK_PREFIX);
    logger.info(`[MovimentosStock] 📦 Total movimentos no banco: ${todosMovimentos.length}`);
    
    let movimentos = todosMovimentos.filter((m) => m && m.empresaId === empresaId);
    logger.info(`[MovimentosStock] 📦 Movimentos da empresa ${empresaId}: ${movimentos.length}`);

    // Aplicar filtros
    if (filtros?.tipo) {
      movimentos = movimentos.filter((m) => m.tipo === filtros.tipo);
      logger.info(`[MovimentosStock] 🔍 Após filtro tipo "${filtros.tipo}": ${movimentos.length}`);
    }
    
    if (filtros?.artigoId) {
      movimentos = movimentos.filter((m) => m.artigoId === filtros.artigoId);
      logger.info(`[MovimentosStock] 🔍 Após filtro artigoId "${filtros.artigoId}": ${movimentos.length}`);
    }
    
    if (filtros?.motivo) {
      movimentos = movimentos.filter((m) => m.motivo === filtros.motivo);
      logger.info(`[MovimentosStock] 🔍 Após filtro motivo "${filtros.motivo}": ${movimentos.length}`);
    }

    if (filtros?.documentoTipo) {
      const tipoDocumento = filtros.documentoTipo.trim().toLowerCase();
      movimentos = movimentos.filter((m) => (m.documentoTipo || "").trim().toLowerCase() === tipoDocumento);
    }

    if (filtros?.documentoNumero) {
      const numeroDocumento = filtros.documentoNumero.trim().toLowerCase();
      movimentos = movimentos.filter((m) => (m.documentoNumero || "").trim().toLowerCase().includes(numeroDocumento));
    }

    if (filtros?.documentoId) {
      movimentos = movimentos.filter((m) => (m as any).documentoId === filtros.documentoId);
    }

    if (filtros?.dataInicio) {
      movimentos = movimentos.filter((m) => m.dataMovimento >= filtros.dataInicio!);
      logger.info(`[MovimentosStock] 🔍 Após filtro dataInicio "${filtros.dataInicio}": ${movimentos.length}`);
    }

    if (filtros?.dataFim) {
      movimentos = movimentos.filter((m) => m.dataMovimento <= filtros.dataFim!);
      logger.info(`[MovimentosStock] 🔍 Após filtro dataFim "${filtros.dataFim}": ${movimentos.length}`);
    }

    // Ordenar por data (mais recentes primeiro)
    movimentos.sort((a, b) => b.dataMovimento.localeCompare(a.dataMovimento));

    logger.info(`[MovimentosStock] ✅ Movimentos finais: ${movimentos.length}`);
    return movimentos;
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao listar movimentos:", error);
    return [];
  }
}

// Alias para compatibilidade
export const listarMovimentosPorEmpresa = listarMovimentos;

/**
 * Obter resumo de movimentos por artigo
 */
export async function obterResumoMovimentos(
  empresaId: string,
  artigoId: string
): Promise<{
  totalEntradas: number;
  totalSaidas: number;
  saldoAtual: number;
}> {
  try {
    const movimentos = await listarMovimentos(empresaId, { artigoId });
    
    const totalEntradas = movimentos
      .filter((m) => m.tipo === "entrada")
      .reduce((sum, m) => sum + m.quantidade, 0);
    
    const totalSaidas = movimentos
      .filter((m) => m.tipo === "saida")
      .reduce((sum, m) => sum + m.quantidade, 0);
    
    const saldoAtual = totalEntradas - totalSaidas;

    return { totalEntradas, totalSaidas, saldoAtual };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao obter resumo:", error);
    return { totalEntradas: 0, totalSaidas: 0, saldoAtual: 0 };
  }
}

export async function reverterMovimentoOperacional(
  id: string,
  dados?: {
    responsavel?: string;
    observacoes?: string;
  },
): Promise<{ success: boolean; data?: { movimentoOriginal: MovimentoStock; movimentoReversao: MovimentoStock }; error?: string }> {
  const lotesRestaurados: Array<{
    loteId: string;
    quantidadeAnterior: number;
    lote?: string;
    dataValidade?: string;
    dataFabricacao?: string;
    custoUnitario: number;
    fornecedorId?: string;
    documentoCompraId?: string;
    localizacao?: string;
  }> = [];

  let movimentoOriginal: MovimentoStock | null = null;
  let movimentoReversao: MovimentoStock | null = null;
  let stockArmazemAtualizado = false;

  try {
    movimentoOriginal = await buscarMovimentoPorId(id);

    if (!movimentoOriginal) {
      return { success: false, error: "Movimento não encontrado" };
    }

    if (movimentoOriginal.movimentoOriginalId) {
      return { success: false, error: "Movimentos de reversão não podem ser revertidos por esta operação" };
    }

    if (movimentoOriginal.revertidoEm || movimentoOriginal.movimentoReversaoId) {
      return { success: false, error: "Este movimento já foi revertido" };
    }

    if (movimentoOriginal.tipo !== "saida" || movimentoOriginal.motivo !== "perda_vencimento") {
      return { success: false, error: "A reversão controlada está disponível apenas para perdas por vencimento" };
    }

    const validacaoContabil = await verificarSemLancamentoContabilDefinitivo({
      empresaId: movimentoOriginal.empresaId,
      documentoId: movimentoOriginal.id,
      rotuloDocumento: "Movimento de stock",
    });
    if (!validacaoContabil.pode) {
      return { success: false, error: validacaoContabil.motivo };
    }

    const artigo = await buscarArtigoPorId(movimentoOriginal.artigoId);
    if (!artigo) {
      return { success: false, error: "Artigo não encontrado para reversão" };
    }

    const armazem = movimentoOriginal.armazemId
      ? await buscarArmazemPorId(movimentoOriginal.armazemId, movimentoOriginal.empresaId)
      : null;

    const lotesParaRestaurar = movimentoOriginal.lotesConsumidos && movimentoOriginal.lotesConsumidos.length > 0
      ? movimentoOriginal.lotesConsumidos
      : movimentoOriginal.loteId
        ? [{ loteId: movimentoOriginal.loteId, quantidade: movimentoOriginal.quantidade }]
        : [];

    if (lotesParaRestaurar.length === 0) {
      return { success: false, error: "O movimento não possui rastreabilidade de lote para reversão" };
    }

    for (const loteMovimento of lotesParaRestaurar) {
      const loteAtual = await stockLotes.buscarLotePorId(loteMovimento.loteId);
      if (!loteAtual) {
        throw new Error(`Lote ${loteMovimento.loteId} não encontrado para reversão`);
      }

      lotesRestaurados.push({
        loteId: loteAtual.id,
        quantidadeAnterior: loteAtual.quantidade,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
      });

      await stockLotes.upsertLote({
        empresaId: loteAtual.empresaId,
        artigoId: loteAtual.artigoId,
        armazemId: loteAtual.armazemId,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        quantidade: loteAtual.quantidade + loteMovimento.quantidade,
        quantidadeReservada: loteAtual.quantidadeReservada,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
        status: loteAtual.status,
      });
    }

    if (armazem) {
      const resultadoStockArmazem = await stockArmazem.atualizarStockArmazem({
        empresaId: movimentoOriginal.empresaId,
        armazemId: armazem.id,
        armazemCodigo: armazem.codigo,
        armazemNome: armazem.nome,
        artigoId: movimentoOriginal.artigoId,
        artigoCodigo: movimentoOriginal.artigoCodigo,
        artigoNome: movimentoOriginal.artigoNome,
        quantidadeDelta: movimentoOriginal.quantidade,
      });

      if (!resultadoStockArmazem.success) {
        throw new Error(resultadoStockArmazem.error || "Erro ao restaurar stock do armazém");
      }

      stockArmazemAtualizado = true;

      const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(
        movimentoOriginal.empresaId,
        movimentoOriginal.artigoId,
      );
      await atualizarEstoque(movimentoOriginal.artigoId, stockTotalRecalculado, "definir");
    } else {
      const resultadoEstoque = await atualizarEstoque(
        movimentoOriginal.artigoId,
        movimentoOriginal.quantidade,
        "adicionar",
      );

      if (!resultadoEstoque.success) {
        throw new Error(resultadoEstoque.error || "Erro ao restaurar estoque do artigo");
      }
    }

    const agora = new Date().toISOString();
    movimentoReversao = {
      id: `movimento_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      empresaId: movimentoOriginal.empresaId,
      artigoId: movimentoOriginal.artigoId,
      loteId: movimentoOriginal.loteId,
      artigoCodigo: movimentoOriginal.artigoCodigo,
      artigoNome: movimentoOriginal.artigoNome,
      tipo: "entrada",
      quantidade: movimentoOriginal.quantidade,
      motivo: "ajuste_positivo",
      documentoTipo: "reversao_operacional",
      documentoNumero: `REV-${movimentoOriginal.id}`,
      armazemId: movimentoOriginal.armazemId,
      armazemCodigo: movimentoOriginal.armazemCodigo,
      armazemNome: movimentoOriginal.armazemNome,
      observacoes:
        `Reversão controlada do movimento ${movimentoOriginal.id}. ` +
        `${dados?.observacoes?.trim() || "Correção de erro operacional."}`,
      responsavel: dados?.responsavel || "Supervisor",
      lotesConsumidos: lotesParaRestaurar.map((lote) => ({
        loteId: lote.loteId,
        lote: lotesRestaurados.find((item) => item.loteId === lote.loteId)?.lote,
        dataValidade: lotesRestaurados.find((item) => item.loteId === lote.loteId)?.dataValidade,
        quantidade: lote.quantidade,
      })),
      movimentoOriginalId: movimentoOriginal.id,
      dataCriacao: agora,
      dataMovimento: agora.split("T")[0],
    };

    await kv.set(`${MOVIMENTOS_STOCK_PREFIX}${movimentoReversao.id}`, movimentoReversao);

    const movimentoOriginalAtualizado: MovimentoStock = {
      ...movimentoOriginal,
      movimentoReversaoId: movimentoReversao.id,
      revertidoEm: agora,
    };

    await kv.set(`${MOVIMENTOS_STOCK_PREFIX}${movimentoOriginal.id}`, movimentoOriginalAtualizado);

    return {
      success: true,
      data: {
        movimentoOriginal: movimentoOriginalAtualizado,
        movimentoReversao,
      },
    };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao reverter movimento operacional:", error);

    if (movimentoReversao) {
      await kv.del(`${MOVIMENTOS_STOCK_PREFIX}${movimentoReversao.id}`);
    }

    if (stockArmazemAtualizado && movimentoOriginal?.armazemId) {
      const armazem = await buscarArmazemPorId(movimentoOriginal.armazemId, movimentoOriginal.empresaId);
      if (armazem) {
        await stockArmazem.atualizarStockArmazem({
          empresaId: movimentoOriginal.empresaId,
          armazemId: armazem.id,
          armazemCodigo: armazem.codigo,
          armazemNome: armazem.nome,
          artigoId: movimentoOriginal.artigoId,
          artigoCodigo: movimentoOriginal.artigoCodigo,
          artigoNome: movimentoOriginal.artigoNome,
          quantidadeDelta: -movimentoOriginal.quantidade,
        });

        const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(
          movimentoOriginal.empresaId,
          movimentoOriginal.artigoId,
        );
        await atualizarEstoque(movimentoOriginal.artigoId, stockTotalRecalculado, "definir");
      }
    }

    for (const lote of lotesRestaurados) {
      const loteAtual = await stockLotes.buscarLotePorId(lote.loteId);
      if (!loteAtual) continue;

      await stockLotes.upsertLote({
        empresaId: loteAtual.empresaId,
        artigoId: loteAtual.artigoId,
        armazemId: loteAtual.armazemId,
        lote: lote.lote,
        dataValidade: lote.dataValidade,
        dataFabricacao: lote.dataFabricacao,
        quantidade: lote.quantidadeAnterior,
        quantidadeReservada: loteAtual.quantidadeReservada,
        custoUnitario: lote.custoUnitario,
        fornecedorId: lote.fornecedorId,
        documentoCompraId: lote.documentoCompraId,
        localizacao: lote.localizacao,
        status: loteAtual.status,
      });
    }

    return { success: false, error: String(error) };
  }
}

export async function reverterMovimentoDocumento(
  id: string,
  dados?: {
    responsavel?: string;
    observacoes?: string;
    documentoTipoReversao?: string;
    documentoNumeroReversao?: string;
  },
): Promise<{ success: boolean; data?: { movimentoOriginal: MovimentoStock; movimentoReversao: MovimentoStock }; error?: string }> {
  const lotesRestaurados: Array<{
    loteId: string;
    quantidadeAnterior: number;
    lote?: string;
    dataValidade?: string;
    dataFabricacao?: string;
    custoUnitario: number;
    fornecedorId?: string;
    documentoCompraId?: string;
    localizacao?: string;
    status?: string;
  }> = [];

  let movimentoOriginal: MovimentoStock | null = null;
  let movimentoReversao: MovimentoStock | null = null;
  let stockArmazemAtualizado = false;

  try {
    movimentoOriginal = await buscarMovimentoPorId(id);

    if (!movimentoOriginal) {
      return { success: false, error: "Movimento não encontrado" };
    }

    if (movimentoOriginal.movimentoOriginalId) {
      return { success: false, error: "Movimentos de reversão não podem ser revertidos por esta operação" };
    }

    if (movimentoOriginal.revertidoEm || movimentoOriginal.movimentoReversaoId) {
      return { success: false, error: "Este movimento já foi revertido" };
    }

    if (movimentoOriginal.tipo !== "saida") {
      return { success: false, error: "A reversão de documento está disponível apenas para movimentos de saída" };
    }

    const validacaoContabilReversaoDocumento = await verificarSemLancamentoContabilDefinitivo({
      empresaId: movimentoOriginal.empresaId,
      documentoId: movimentoOriginal.id,
      numeroDocumento: movimentoOriginal.documentoNumero,
      rotuloDocumento: "Movimento de stock",
    });
    if (!validacaoContabilReversaoDocumento.pode) {
      return { success: false, error: validacaoContabilReversaoDocumento.motivo };
    }

    const artigo = await buscarArtigoPorId(movimentoOriginal.artigoId);
    if (!artigo) {
      return { success: false, error: "Artigo não encontrado para reversão" };
    }

    const armazem = movimentoOriginal.armazemId
      ? await buscarArmazemPorId(movimentoOriginal.armazemId, movimentoOriginal.empresaId)
      : null;

    const lotesParaRestaurar = movimentoOriginal.lotesConsumidos && movimentoOriginal.lotesConsumidos.length > 0
      ? movimentoOriginal.lotesConsumidos
      : movimentoOriginal.loteId
        ? [{ loteId: movimentoOriginal.loteId, quantidade: movimentoOriginal.quantidade }]
        : [];

    for (const loteMovimento of lotesParaRestaurar) {
      const loteAtual = await stockLotes.buscarLotePorId(loteMovimento.loteId);
      if (!loteAtual) {
        throw new Error(`Lote ${loteMovimento.loteId} não encontrado para reversão`);
      }

      lotesRestaurados.push({
        loteId: loteAtual.id,
        quantidadeAnterior: loteAtual.quantidade,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
        status: loteAtual.status,
      });

      await stockLotes.upsertLote({
        empresaId: loteAtual.empresaId,
        artigoId: loteAtual.artigoId,
        armazemId: loteAtual.armazemId,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        quantidade: loteAtual.quantidade + loteMovimento.quantidade,
        quantidadeReservada: loteAtual.quantidadeReservada,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
        status: loteAtual.status,
      });
    }

    if (armazem) {
      const resultadoStockArmazem = await stockArmazem.atualizarStockArmazem({
        empresaId: movimentoOriginal.empresaId,
        armazemId: armazem.id,
        armazemCodigo: armazem.codigo,
        armazemNome: armazem.nome,
        artigoId: movimentoOriginal.artigoId,
        artigoCodigo: movimentoOriginal.artigoCodigo,
        artigoNome: movimentoOriginal.artigoNome,
        quantidadeDelta: movimentoOriginal.quantidade,
      });

      if (!resultadoStockArmazem.success) {
        throw new Error(resultadoStockArmazem.error || "Erro ao restaurar stock do armazém");
      }

      stockArmazemAtualizado = true;

      const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(
        movimentoOriginal.empresaId,
        movimentoOriginal.artigoId,
      );
      await atualizarEstoque(movimentoOriginal.artigoId, stockTotalRecalculado, "definir");
    } else {
      const resultadoEstoque = await atualizarEstoque(
        movimentoOriginal.artigoId,
        movimentoOriginal.quantidade,
        "adicionar",
      );

      if (!resultadoEstoque.success) {
        throw new Error(resultadoEstoque.error || "Erro ao restaurar estoque do artigo");
      }
    }

    const agora = new Date().toISOString();
    movimentoReversao = {
      id: `movimento_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      empresaId: movimentoOriginal.empresaId,
      artigoId: movimentoOriginal.artigoId,
      loteId: movimentoOriginal.loteId,
      artigoCodigo: movimentoOriginal.artigoCodigo,
      artigoNome: movimentoOriginal.artigoNome,
      tipo: "entrada",
      quantidade: movimentoOriginal.quantidade,
      motivo: "ajuste_positivo",
      documentoTipo: dados?.documentoTipoReversao || "reversao_documento",
      documentoNumero: dados?.documentoNumeroReversao || movimentoOriginal.documentoNumero || `REV-${movimentoOriginal.id}`,
      armazemId: movimentoOriginal.armazemId,
      armazemCodigo: movimentoOriginal.armazemCodigo,
      armazemNome: movimentoOriginal.armazemNome,
      observacoes:
        `Reversão documental do movimento ${movimentoOriginal.id}. ` +
        `${dados?.observacoes?.trim() || "Anulação do documento de origem."}`,
      responsavel: dados?.responsavel || "Sistema",
      lotesConsumidos: lotesParaRestaurar.length > 0
        ? lotesParaRestaurar.map((lote) => ({
            loteId: lote.loteId,
            lote: lotesRestaurados.find((item) => item.loteId === lote.loteId)?.lote,
            dataValidade: lotesRestaurados.find((item) => item.loteId === lote.loteId)?.dataValidade,
            quantidade: lote.quantidade,
          }))
        : undefined,
      movimentoOriginalId: movimentoOriginal.id,
      dataCriacao: agora,
      dataMovimento: agora.split("T")[0],
    };

    await kv.set(`${MOVIMENTOS_STOCK_PREFIX}${movimentoReversao.id}`, movimentoReversao);

    const movimentoOriginalAtualizado: MovimentoStock = {
      ...movimentoOriginal,
      movimentoReversaoId: movimentoReversao.id,
      revertidoEm: agora,
    };

    await kv.set(`${MOVIMENTOS_STOCK_PREFIX}${movimentoOriginal.id}`, movimentoOriginalAtualizado);

    return {
      success: true,
      data: {
        movimentoOriginal: movimentoOriginalAtualizado,
        movimentoReversao,
      },
    };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao reverter movimento documental:", error);

    if (movimentoReversao) {
      await kv.del(`${MOVIMENTOS_STOCK_PREFIX}${movimentoReversao.id}`);
    }

    if (stockArmazemAtualizado && movimentoOriginal?.armazemId) {
      const armazem = await buscarArmazemPorId(movimentoOriginal.armazemId, movimentoOriginal.empresaId);
      if (armazem) {
        await stockArmazem.atualizarStockArmazem({
          empresaId: movimentoOriginal.empresaId,
          armazemId: armazem.id,
          armazemCodigo: armazem.codigo,
          armazemNome: armazem.nome,
          artigoId: movimentoOriginal.artigoId,
          artigoCodigo: movimentoOriginal.artigoCodigo,
          artigoNome: movimentoOriginal.artigoNome,
          quantidadeDelta: -movimentoOriginal.quantidade,
        });

        const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(
          movimentoOriginal.empresaId,
          movimentoOriginal.artigoId,
        );
        await atualizarEstoque(movimentoOriginal.artigoId, stockTotalRecalculado, "definir");
      }
    }

    for (const lote of lotesRestaurados) {
      const loteAtual = await stockLotes.buscarLotePorId(lote.loteId);
      if (!loteAtual) continue;

      await stockLotes.upsertLote({
        empresaId: loteAtual.empresaId,
        artigoId: loteAtual.artigoId,
        armazemId: loteAtual.armazemId,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        quantidade: lote.quantidadeAnterior,
        quantidadeReservada: loteAtual.quantidadeReservada,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
        status: lote.status || loteAtual.status,
      });
    }

    return { success: false, error: String(error) };
  }
}

export async function reverterMovimentosPorDocumento(
  empresaId: string,
  documentoNumero: string,
  documentoTipo?: string,
  dados?: {
    responsavel?: string;
    observacoes?: string;
    documentoTipoReversao?: string;
    documentoNumeroReversao?: string;
  },
): Promise<{ success: boolean; revertidos: number; erros: string[] }> {
  try {
    const todosMovimentos = await kv.getByPrefix<MovimentoStock>(MOVIMENTOS_STOCK_PREFIX);
    const movimentosDocumento = todosMovimentos.filter(
      (movimento) =>
        movimento.empresaId === empresaId &&
        movimento.documentoNumero === documentoNumero &&
        (!documentoTipo || movimento.documentoTipo === documentoTipo) &&
        !movimento.movimentoOriginalId,
    );

    let revertidos = 0;
    const erros: string[] = [];

    for (const movimento of movimentosDocumento) {
      const resultado = await reverterMovimentoDocumento(movimento.id, dados);

      if (!resultado.success) {
        erros.push(`${movimento.id}: ${resultado.error}`);
        continue;
      }

      revertidos++;
    }

    return {
      success: erros.length === 0,
      revertidos,
      erros,
    };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao reverter movimentos por documento:", error);
    return { success: false, revertidos: 0, erros: [String(error)] };
  }
}

function normalizarTextoLote(lote?: string): string {
  return lote?.trim().toUpperCase() || "";
}

async function restaurarLotesStock(snapshots: stockLotes.StockLote[]): Promise<void> {
  for (const lote of snapshots) {
    await stockLotes.upsertLote({
      empresaId: lote.empresaId,
      artigoId: lote.artigoId,
      armazemId: lote.armazemId,
      lote: lote.lote,
      dataValidade: lote.dataValidade,
      dataFabricacao: lote.dataFabricacao,
      quantidade: lote.quantidade,
      quantidadeReservada: lote.quantidadeReservada,
      custoUnitario: lote.custoUnitario,
      fornecedorId: lote.fornecedorId,
      documentoCompraId: lote.documentoCompraId,
      localizacao: lote.localizacao,
      status: lote.status,
    });
  }
}

async function ajustarLotesAoEliminarMovimento(movimento: MovimentoStock): Promise<{
  success: boolean;
  snapshots: stockLotes.StockLote[];
  error?: string;
}> {
  const snapshots: stockLotes.StockLote[] = [];

  const referencias = movimento.lotesConsumidos && movimento.lotesConsumidos.length > 0
    ? movimento.lotesConsumidos
    : movimento.loteId
      ? [{ loteId: movimento.loteId, lote: movimento.lote, quantidade: movimento.quantidade }]
      : [];

  if (movimento.tipo === "saida") {
    for (const referencia of referencias) {
      if (!referencia.loteId || !Number.isFinite(referencia.quantidade) || referencia.quantidade <= 0) continue;

      const loteAtual = await stockLotes.buscarLotePorId(referencia.loteId);
      if (!loteAtual) {
        return { success: false, snapshots, error: `Lote ${referencia.loteId} nao encontrado para repor a saida` };
      }

      snapshots.push({ ...loteAtual });
      await stockLotes.upsertLote({
        empresaId: loteAtual.empresaId,
        artigoId: loteAtual.artigoId,
        armazemId: loteAtual.armazemId,
        lote: loteAtual.lote,
        dataValidade: loteAtual.dataValidade,
        dataFabricacao: loteAtual.dataFabricacao,
        quantidade: loteAtual.quantidade + referencia.quantidade,
        quantidadeReservada: loteAtual.quantidadeReservada,
        custoUnitario: loteAtual.custoUnitario,
        fornecedorId: loteAtual.fornecedorId,
        documentoCompraId: loteAtual.documentoCompraId,
        localizacao: loteAtual.localizacao,
        status: loteAtual.status,
      });
    }

    return { success: true, snapshots };
  }

  const lotesParaReduzir: Array<{ lote: stockLotes.StockLote; quantidade: number }> = [];

  for (const referencia of referencias) {
    if (!referencia.loteId || !Number.isFinite(referencia.quantidade) || referencia.quantidade <= 0) continue;

    const loteAtual = await stockLotes.buscarLotePorId(referencia.loteId);
    if (!loteAtual) {
      return { success: false, snapshots, error: `Lote ${referencia.loteId} nao encontrado para remover a entrada` };
    }

    lotesParaReduzir.push({ lote: loteAtual, quantidade: referencia.quantidade });
  }

  if (lotesParaReduzir.length === 0 && movimento.lote && movimento.armazemId) {
    const candidatos = (await stockLotes.listarLotes(movimento.empresaId, {
      artigoId: movimento.artigoId,
      armazemId: movimento.armazemId,
      incluirExpirados: true,
    })).filter((lote) => normalizarTextoLote(lote.lote) === normalizarTextoLote(movimento.lote));

    if (candidatos.length > 1) {
      return {
        success: false,
        snapshots,
        error: `Existem varios lotes com o codigo ${movimento.lote}. Reverta pelo documento de origem para evitar abater o lote errado.`,
      };
    }

    if (candidatos.length === 1) {
      lotesParaReduzir.push({ lote: candidatos[0], quantidade: movimento.quantidade });
    }
  }

  for (const item of lotesParaReduzir) {
    const novaQuantidade = item.lote.quantidade - item.quantidade;
    if (novaQuantidade < 0) {
      return { success: false, snapshots, error: `Lote ${item.lote.lote || item.lote.id} sem saldo suficiente para remover a entrada` };
    }
    if (novaQuantidade < item.lote.quantidadeReservada) {
      return { success: false, snapshots, error: `Lote ${item.lote.lote || item.lote.id} possui reserva superior ao saldo apos a remocao` };
    }

    snapshots.push({ ...item.lote });
    await stockLotes.upsertLote({
      empresaId: item.lote.empresaId,
      artigoId: item.lote.artigoId,
      armazemId: item.lote.armazemId,
      lote: item.lote.lote,
      dataValidade: item.lote.dataValidade,
      dataFabricacao: item.lote.dataFabricacao,
      quantidade: novaQuantidade,
      quantidadeReservada: item.lote.quantidadeReservada,
      custoUnitario: item.lote.custoUnitario,
      fornecedorId: item.lote.fornecedorId,
      documentoCompraId: item.lote.documentoCompraId,
      localizacao: item.lote.localizacao,
      status: item.lote.status,
    });
  }

  return { success: true, snapshots };
}
/**
 * Deletar movimento (e reverter estoque)
 */
export async function deletarMovimento(id: string): Promise<{ success: boolean; error?: string }> {
  let movimento: MovimentoStock | null = null;
  let stockArmazemAnterior: stockArmazem.StockArmazem | null = null;
  let stockArmazemAtualizado = false;
  let lotesSnapshots: stockLotes.StockLote[] = [];

  try {
    movimento = await buscarMovimentoPorId(id);

    if (!movimento) {
      return { success: false, error: "Movimento nao encontrado" };
    }

    const validacaoContabil = await verificarSemLancamentoContabilDefinitivo({
      empresaId: movimento.empresaId,
      documentoId: movimento.id,
      rotuloDocumento: "Movimento de stock",
    });
    if (!validacaoContabil.pode) {
      return { success: false, error: validacaoContabil.motivo };
    }

    const artigo = await buscarArtigoPorId(movimento.artigoId);
    const ajusteLotes = await ajustarLotesAoEliminarMovimento(movimento);
    if (!ajusteLotes.success) {
      return { success: false, error: ajusteLotes.error };
    }
    lotesSnapshots = ajusteLotes.snapshots;

    if (movimento.armazemId) {
      stockArmazemAnterior = await stockArmazem.buscarStockArtigoArmazem(
        movimento.empresaId,
        movimento.artigoId,
        movimento.armazemId,
      );

      const quantidadeDelta = movimento.tipo === "entrada"
        ? -movimento.quantidade
        : movimento.quantidade;

      const resultadoStockArmazem = await stockArmazem.atualizarStockArmazem({
        empresaId: movimento.empresaId,
        armazemId: movimento.armazemId,
        armazemCodigo: movimento.armazemCodigo || "",
        armazemNome: movimento.armazemNome || "",
        artigoId: movimento.artigoId,
        artigoCodigo: movimento.artigoCodigo,
        artigoNome: movimento.artigoNome,
        quantidadeDelta,
      });

      if (!resultadoStockArmazem.success) {
        throw new Error(resultadoStockArmazem.error || "Erro ao reverter stock do armazem");
      }
      stockArmazemAtualizado = true;

      const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(movimento.empresaId, movimento.artigoId);
      const resultadoArtigo = await atualizarEstoque(movimento.artigoId, stockTotalRecalculado, "definir");
      if (!resultadoArtigo.success && !resultadoArtigo.error?.includes("Artigo")) {
        throw new Error(resultadoArtigo.error || "Erro ao sincronizar stock geral do artigo");
      }
    } else if (artigo) {
      if (movimento.tipo === "entrada" && (artigo.estoqueAtual || 0) < movimento.quantidade) {
        throw new Error(`Nao e possivel eliminar a entrada ${movimento.id}: stock atual insuficiente para reverter.`);
      }

      const operacaoReversa = movimento.tipo === "entrada" ? "remover" : "adicionar";
      const resultadoEstoque = await atualizarEstoque(
        movimento.artigoId,
        movimento.quantidade,
        operacaoReversa,
      );

      if (!resultadoEstoque.success) {
        throw new Error(`Erro ao reverter estoque: ${resultadoEstoque.error}`);
      }
    }

    await kv.del(`${MOVIMENTOS_STOCK_PREFIX}${id}`);

    return { success: true };
  } catch (error) {
    logger.error("[MovimentosStock] Erro ao deletar movimento:", error);

    if (stockArmazemAtualizado && movimento?.armazemId) {
      if (stockArmazemAnterior) {
        await stockArmazem.upsertStock({
          empresaId: movimento.empresaId,
          artigoId: movimento.artigoId,
          armazemId: movimento.armazemId,
          quantidade: stockArmazemAnterior.quantidade,
          quantidadeReservada: stockArmazemAnterior.quantidadeReservada,
          custoMedio: stockArmazemAnterior.custoMedio,
          localizacao: stockArmazemAnterior.localizacao,
          lote: stockArmazemAnterior.lote,
          dataValidade: stockArmazemAnterior.dataValidade,
        });
      } else {
        const stockCriado = await stockArmazem.buscarStockArtigoArmazem(
          movimento.empresaId,
          movimento.artigoId,
          movimento.armazemId,
        );
        if (stockCriado) {
          await stockArmazem.deletarStock(stockCriado.id);
        }
      }

      const stockTotalRecalculado = await stockArmazem.obterStockTotalArtigo(movimento.empresaId, movimento.artigoId);
      await atualizarEstoque(movimento.artigoId, stockTotalRecalculado, "definir");
    }

    if (lotesSnapshots.length > 0) {
      await restaurarLotesStock(lotesSnapshots);
    }

    return { success: false, error: error instanceof Error ? error.message : String(error) };
  }
}

/**
 * Eliminar todos os movimentos de stock relacionados a um documento
 * (usado ao eliminar Facturas, VD, Notas, etc)
 */
export async function eliminarMovimentosPorDocumento(
  empresaId: string,
  documentoNumero: string,
  documentoTipo?: string
): Promise<{ success: boolean; eliminados: number; error?: string }> {
  try {
    logger.info(`[MovimentosStock] 🗑️ Eliminando movimentos do documento ${documentoTipo || ''} ${documentoNumero}...`);
    
    // Buscar todos os movimentos do documento
    const todosMovimentos = await kv.getByPrefix<MovimentoStock>(MOVIMENTOS_STOCK_PREFIX);
    const movimentosDocumento = todosMovimentos.filter(
      (m) => 
        m.empresaId === empresaId && 
        m.documentoNumero === documentoNumero &&
        (!documentoTipo || m.documentoTipo === documentoTipo)
    );

    if (movimentosDocumento.length === 0) {
      logger.info(`[MovimentosStock] ℹ️ Nenhum movimento encontrado para o documento ${documentoNumero}`);
      return { success: true, eliminados: 0 };
    }

    logger.info(`[MovimentosStock] 📦 Encontrados ${movimentosDocumento.length} movimentos para eliminar`);

    let eliminados = 0;
    const erros: string[] = [];

    // Eliminar cada movimento (revertendo o stock)
    for (const movimento of movimentosDocumento) {
      const resultado = await deletarMovimento(movimento.id);
      
      if (resultado.success) {
        eliminados++;
        logger.info(`[MovimentosStock] ✅ Movimento ${movimento.id} eliminado (${movimento.artigoCodigo} - ${movimento.quantidade} un)`);
      } else {
        erros.push(`${movimento.id}: ${resultado.error}`);
        logger.error(`[MovimentosStock] ❌ Erro ao eliminar movimento ${movimento.id}:`, resultado.error);
      }
    }

    if (erros.length > 0) {
      return { 
        success: false, 
        eliminados, 
        error: `Eliminados ${eliminados}/${movimentosDocumento.length}. Erros: ${erros.join('; ')}` 
      };
    }

    logger.info(`[MovimentosStock] ✅ ${eliminados} movimentos eliminados com sucesso`);
    return { success: true, eliminados };
  } catch (error) {
    logger.error("[MovimentosStock] ❌ Erro ao eliminar movimentos por documento:", error);
    return { success: false, eliminados: 0, error: String(error) };
  }
}

/**
 * 🗑️ APAGAR TODOS OS MOVIMENTOS SEM REVERTER STOCK
 * Uso: Testes, desenvolvimento, reset completo
 * 
 * ⚠️ ATENÇÃO: Esta função NÃO reverte o stock!
 * Apenas elimina os registros de movimentos do histórico.
 */
export async function apagarTodosSemReverterStock(
  empresaId: string
): Promise<{ success: boolean; eliminados: number; error?: string }> {
  try {
    logger.info(`[MovimentosStock] 🗑️ APAGANDO TODOS os movimentos de ${empresaId} SEM REVERTER STOCK...`);
    
    // ✅ BUSCAR COM CHAVES EXATAS DO BANCO
    const todosMovimentosComChaves = await kv.getByPrefixWithKeys<MovimentoStock>(MOVIMENTOS_STOCK_PREFIX);
    logger.info(`[MovimentosStock] 🔍 Total de registros no KV: ${todosMovimentosComChaves.length}`);
    logger.info(`[MovimentosStock] 🔍 Prefixo usado: "${MOVIMENTOS_STOCK_PREFIX}"`);
    
    // Filtrar movimentos da empresa
    const movimentosDaEmpresa = todosMovimentosComChaves.filter(item => item.value.empresaId === empresaId);

    logger.info(`[MovimentosStock] 📊 Total de movimentos encontrados para empresa "${empresaId}": ${movimentosDaEmpresa.length}`);
    
    // Debug: listar as CHAVES EXATAS do banco
    if (movimentosDaEmpresa.length > 0) {
      logger.info(`[MovimentosStock] 🔑 CHAVES EXATAS no banco:`, movimentosDaEmpresa.map(m => m.key));
    }

    if (movimentosDaEmpresa.length === 0) {
      logger.info(`[MovimentosStock] ℹ️ Nenhum movimento encontrado para empresa ${empresaId}`);
      return { success: true, eliminados: 0 };
    }

    // ✅ DELETAR USANDO CHAVES EXATAS DO BANCO
    logger.info(`[MovimentosStock] 🗑️ Iniciando eliminação de ${movimentosDaEmpresa.length} movimentos...`);
    
    const chavesParaDeletar = movimentosDaEmpresa.map(m => m.key);
    
    // Usar mdel para deletar múltiplas chaves de uma vez
    await kv.mdel(chavesParaDeletar);
    
    logger.info(`[MovimentosStock] ✅ Comando de eliminação executado para ${chavesParaDeletar.length} chaves`);

    // ✅ VERIFICAÇÃO OBRIGATÓRIA: Conferir se realmente foram eliminados
    const verificacaoComChaves = await kv.getByPrefixWithKeys<MovimentoStock>(MOVIMENTOS_STOCK_PREFIX);
    const restantes = verificacaoComChaves.filter(item => item.value.empresaId === empresaId);
    
    logger.info(`[MovimentosStock] 🔍 VERIFICAÇÃO CRÍTICA: ${restantes.length} movimentos restantes no KV após eliminação`);
    
    if (restantes.length > 0) {
      logger.error(`[MovimentosStock] ❌ FALHA NA ELIMINAÇÃO! ${restantes.length} movimentos NÃO foram eliminados!`);
      logger.error(`[MovimentosStock] 🔑 Chaves que não foram eliminadas:`, restantes.map(m => m.key));
      
      return { 
        success: false, 
        eliminados: chavesParaDeletar.length - restantes.length,
        error: `Apenas ${chavesParaDeletar.length - restantes.length}/${chavesParaDeletar.length} movimentos foram eliminados. ${restantes.length} registros ainda existem no banco.`
      };
    }
    
    logger.info(`[MovimentosStock] ✅ CONFIRMADO: Todos os ${chavesParaDeletar.length} movimentos foram eliminados do banco!`);
    
    return { 
      success: true, 
      eliminados: chavesParaDeletar.length,
      error: undefined 
    };
  } catch (error) {
    logger.error("[MovimentosStock] ❌ Erro ao apagar movimentos:", error);
    return { 
      success: false, 
      eliminados: 0, 
      error: String(error) 
    };
  }
}
