﻿import * as kv from "./kv_store.tsx";
import * as stockArmazem from "./stock-armazem.tsx";
import {
  type PosValidadeConfig,
  obterConfiguracaoPosValidade,
  obterConfiguracaoPosValidadePadrao,
} from "./pos-validade-config.tsx";

const STOCK_LOTE_PREFIX = "stocklote_";
const LOTE_VAZIO = "__sem_lote__";

export type StatusStockLote = "ativo" | "expirado" | "bloqueado" | "promocao";
export type NivelAlertaValidade = "normal" | "atencao" | "critico" | "expirado";

export interface StockLote {
  id: string;
  empresaId: string;
  artigoId: string;
  armazemId: string;
  lote?: string;
  dataValidade?: string;
  dataFabricacao?: string;
  quantidade: number;
  quantidadeReservada: number;
  quantidadeDisponivel: number;
  custoUnitario: number;
  fornecedorId?: string;
  documentoCompraId?: string;
  localizacao?: string;
  status: StatusStockLote;
  criadoEm: string;
  atualizadoEm: string;
}

export interface ResumoLoteArtigo {
  artigoId: string;
  totalLotes: number;
  quantidadeTotal: number;
  quantidadeDisponivel: number;
  quantidadeDisponivelValida: number;
  quantidadeExpirada: number;
  proximaValidade?: string;
  diasParaProximaValidade?: number;
  nivelAlertaValidade: NivelAlertaValidade;
  alertaValidade?: string;
  descontoValidadeSugerido: number;
  temLotes: boolean;
}

export interface PoliticaDescontoValidade {
  diasLimite: number;
  desconto: number;
  etiqueta: string;
}

export interface PoliticaFaixaValidadeResumo {
  codigo: string;
  titulo: string;
  mostrarNoPos: boolean;
  permitirVenda: boolean;
  exigirSupervisor: boolean;
  desconto: number;
  etiqueta: string;
}

export interface AlertaValidadeLote extends StockLote {
  diasParaValidade: number;
  nivelAlerta: NivelAlertaValidade;
  alerta: string;
  descontoSugerido: number;
}

export interface PlanoConsumoLote {
  loteId: string;
  artigoId: string;
  armazemId: string;
  lote?: string;
  dataValidade?: string;
  quantidade: number;
}

export interface ResultadoPlanoConsumoFEFO {
  success: boolean;
  temLotes: boolean;
  plano: PlanoConsumoLote[];
  quantidadePlaneada: number;
  error?: string;
}

export type MetodoCusteioStock = "custo_medio" | "fifo" | "fefo" | "lifo" | "manual";

export interface ResultadoPlanoConsumoLote {
  success: boolean;
  plano?: PlanoConsumoLote;
  error?: string;
}

export interface ResultadoTransferenciaLote {
  success: boolean;
  loteOrigem?: StockLote;
  loteDestino?: StockLote;
  error?: string;
}

function gerarId(): string {
  return `lote_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
}

function normalizarLote(lote?: string): string {
  const valor = lote?.trim();
  return valor ? valor.toUpperCase() : LOTE_VAZIO;
}

function normalizarData(data?: string): string {
  return data?.trim() || "";
}

function hojeISO(): string {
  return new Date().toISOString().split("T")[0];
}

function calcularDiasParaValidade(dataValidade?: string): number | undefined {
  if (!dataValidade) return undefined;

  const hoje = new Date(`${hojeISO()}T00:00:00`);
  const data = new Date(`${dataValidade}T00:00:00`);
  return Math.floor((data.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24));
}

function obterPoliticasPromocao(): PoliticaDescontoValidade[] {
  return [];
}

export function obterPoliticaFaixaValidade(
  diasParaValidade?: number,
  config?: Pick<PosValidadeConfig, "politicasFaixa">,
): PoliticaFaixaValidadeResumo | undefined {
  if (diasParaValidade === undefined) {
    return undefined;
  }

  const configuracao = config || obterConfiguracaoPosValidadePadrao("__default__");
  const politicas = configuracao.politicasFaixa || [];
  const politica = politicas.find((item) => {
    const minOk = item.diasMin === undefined || diasParaValidade >= item.diasMin;
    const maxOk = item.diasMax === undefined || diasParaValidade <= item.diasMax;
    return minOk && maxOk;
  });

  if (!politica) {
    return undefined;
  }

  return {
    codigo: politica.codigo,
    titulo: politica.titulo,
    mostrarNoPos: politica.mostrarNoPos,
    permitirVenda: politica.permitirVenda,
    exigirSupervisor: politica.exigirSupervisor,
    desconto: politica.desconto,
    etiqueta: politica.etiqueta,
  };
}

export function obterNivelAlertaValidade(
  diasParaValidade?: number,
  config?: Pick<PosValidadeConfig, "diasAlertaCritico" | "diasAlertaAtencao">,
): NivelAlertaValidade {
  const configuracao = config || obterConfiguracaoPosValidadePadrao("__default__");
  if (diasParaValidade === undefined) return "normal";
  if (diasParaValidade < 0) return "expirado";
  if (diasParaValidade <= configuracao.diasAlertaCritico) return "critico";
  if (diasParaValidade <= configuracao.diasAlertaAtencao) return "atencao";
  return "normal";
}

export function obterDescontoSugeridoValidade(
  diasParaValidade?: number,
  config?: Pick<PosValidadeConfig, "ativo" | "aplicarDescontoAutomatico" | "regrasPromocao" | "politicasFaixa">,
): number {
  const configuracao = config || obterConfiguracaoPosValidadePadrao("__default__");
  if (diasParaValidade === undefined) {
    return 0;
  }

  if (!configuracao.ativo) {
    return 0;
  }

  const politicaFaixa = obterPoliticaFaixaValidade(diasParaValidade, configuracao);
  if (politicaFaixa) {
    return politicaFaixa.desconto || 0;
  }

  if (!configuracao.aplicarDescontoAutomatico || diasParaValidade < 0) {
    return 0;
  }

  const politica = normalizarPoliticasPromocao(configuracao.regrasPromocao)
    .find((item) => diasParaValidade <= item.diasLimite);

  return politica?.desconto || 0;
}

export function obterMensagemAlertaValidade(diasParaValidade?: number): string | undefined {
  if (diasParaValidade === undefined) return undefined;
  if (diasParaValidade < 0) return "Produto expirado";
  if (diasParaValidade === 0) return "Expira hoje";
  if (diasParaValidade === 1) return "Expira amanhã";
  if (diasParaValidade <= 3) return `Expira em ${diasParaValidade} dias`;
  if (diasParaValidade <= 7) return `Validade crítica: ${diasParaValidade} dias`;
  if (diasParaValidade <= 30) return `Validade próxima: ${diasParaValidade} dias`;
  return undefined;
}

function calcularStatus(dataValidade?: string, statusAtual?: StatusStockLote): StatusStockLote {
  if (statusAtual === "bloqueado") {
    return "bloqueado";
  }

  if (dataValidade && dataValidade < hojeISO()) {
    return "expirado";
  }

  return statusAtual === "promocao" ? "promocao" : "ativo";
}

function normalizarPoliticasPromocao(regras?: PosValidadeConfig["regrasPromocao"]) {
  return (regras && regras.length > 0 ? regras : obterPoliticasPromocao())
    .slice()
    .sort((a, b) => a.diasLimite - b.diasLimite);
}

function calcularQuantidadeDisponivel(quantidade: number, quantidadeReservada: number): number {
  return quantidade - quantidadeReservada;
}

function validarSaldoLote(quantidade: number, quantidadeReservada: number): string | null {
  if (!Number.isFinite(quantidade) || !Number.isFinite(quantidadeReservada)) {
    return "Quantidade de lote invalida";
  }

  if (quantidade < 0) {
    return "Quantidade do lote nao pode ser negativa";
  }

  if (quantidadeReservada < 0) {
    return "Quantidade reservada do lote nao pode ser negativa";
  }

  if (calcularQuantidadeDisponivel(quantidade, quantidadeReservada) < 0) {
    return "Quantidade reservada superior ao saldo do lote";
  }

  return null;
}
function comPrefixo(id: string): string {
  return id.startsWith(STOCK_LOTE_PREFIX) ? id : `${STOCK_LOTE_PREFIX}${id}`;
}

async function salvarLote(lote: StockLote): Promise<void> {
  await kv.set(comPrefixo(lote.id), lote);
}

function ordenarFEFO(lotes: StockLote[]): StockLote[] {
  return [...lotes].sort((a, b) => {
    const aExpirado = a.status === "expirado";
    const bExpirado = b.status === "expirado";

    if (aExpirado !== bExpirado) {
      return aExpirado ? 1 : -1;
    }

    if (a.dataValidade && b.dataValidade) {
      return a.dataValidade.localeCompare(b.dataValidade);
    }

    if (a.dataValidade) return -1;
    if (b.dataValidade) return 1;

    return a.criadoEm.localeCompare(b.criadoEm);
  });
}

function ordenarLotesPorMetodo(lotes: StockLote[], metodo?: MetodoCusteioStock): StockLote[] {
  const metodoNormalizado = metodo || "fefo";

  if (metodoNormalizado === "fifo" || metodoNormalizado === "custo_medio" || metodoNormalizado === "manual") {
    return [...lotes].sort((a, b) =>
      (a.criadoEm || a.atualizadoEm || "").localeCompare(b.criadoEm || b.atualizadoEm || "")
    );
  }

  if (metodoNormalizado === "lifo") {
    return [...lotes].sort((a, b) =>
      (b.criadoEm || b.atualizadoEm || "").localeCompare(a.criadoEm || a.atualizadoEm || "")
    );
  }

  return ordenarFEFO(lotes);
}

export async function listarLotesPorEmpresa(empresaId: string): Promise<StockLote[]> {
  const lotes = await kv.getByPrefix<StockLote>(STOCK_LOTE_PREFIX);
  return lotes.filter((lote) => lote.empresaId === empresaId);
}

export async function listarLotes(
  empresaId: string,
  filtros?: {
    artigoId?: string;
    armazemId?: string;
    incluirExpirados?: boolean;
    somenteDisponivel?: boolean;
  },
): Promise<StockLote[]> {
  const lotes = await listarLotesPorEmpresa(empresaId);

  return ordenarFEFO(
    lotes.filter((lote) => {
      if (filtros?.artigoId && lote.artigoId !== filtros.artigoId) return false;
      if (filtros?.armazemId && lote.armazemId !== filtros.armazemId) return false;
      if (!filtros?.incluirExpirados && lote.status === "expirado") return false;
      if (filtros?.somenteDisponivel && lote.quantidadeDisponivel <= 0) return false;
      return true;
    }),
  );
}

export async function buscarLotePorId(id: string): Promise<StockLote | null> {
  return await kv.get(comPrefixo(id));
}

export async function deletarLote(id: string): Promise<void> {
  await kv.del(comPrefixo(id));
}
export async function buscarLotePorIdentidade(
  empresaId: string,
  artigoId: string,
  armazemId: string,
  lote?: string,
  dataValidade?: string,
): Promise<StockLote | null> {
  const loteNormalizado = normalizarLote(lote);
  const dataNormalizada = normalizarData(dataValidade);
  const lotes = await listarLotes(empresaId, { artigoId, armazemId, incluirExpirados: true });

  return lotes.find((item) =>
    normalizarLote(item.lote) === loteNormalizado &&
    normalizarData(item.dataValidade) === dataNormalizada
  ) || null;
}

export async function upsertLote(dados: {
  empresaId: string;
  artigoId: string;
  armazemId: string;
  lote?: string;
  dataValidade?: string;
  dataFabricacao?: string;
  quantidade: number;
  quantidadeReservada?: number;
  custoUnitario?: number;
  fornecedorId?: string;
  documentoCompraId?: string;
  localizacao?: string;
  status?: StatusStockLote;
}): Promise<StockLote> {
  if (!dados.empresaId || !dados.artigoId || !dados.armazemId) {
    throw new Error("empresaId, artigoId e armazemId sao obrigatorios para lote de stock");
  }

  const existente = await buscarLotePorIdentidade(
    dados.empresaId,
    dados.artigoId,
    dados.armazemId,
    dados.lote,
    dados.dataValidade,
  );

  const agora = new Date().toISOString();
  const quantidade = Number(dados.quantidade);
  const quantidadeReservada = dados.quantidadeReservada ?? existente?.quantidadeReservada ?? 0;
  const erroSaldo = validarSaldoLote(quantidade, quantidadeReservada);
  if (erroSaldo) {
    throw new Error(erroSaldo);
  }

  const custoUnitario = dados.custoUnitario ?? existente?.custoUnitario ?? 0;
  if (!Number.isFinite(custoUnitario) || custoUnitario < 0) {
    throw new Error("Custo unitario do lote invalido");
  }

  const status = calcularStatus(dados.dataValidade, dados.status || existente?.status);

  if (existente) {
    const atualizado: StockLote = {
      ...existente,
      quantidade,
      quantidadeReservada,
      quantidadeDisponivel: calcularQuantidadeDisponivel(quantidade, quantidadeReservada),
      dataFabricacao: dados.dataFabricacao ?? existente.dataFabricacao,
      custoUnitario,
      fornecedorId: dados.fornecedorId ?? existente.fornecedorId,
      documentoCompraId: dados.documentoCompraId ?? existente.documentoCompraId,
      localizacao: dados.localizacao ?? existente.localizacao,
      status,
      atualizadoEm: agora,
    };

    await salvarLote(atualizado);
    return atualizado;
  }

  const novo: StockLote = {
    id: gerarId(),
    empresaId: dados.empresaId,
    artigoId: dados.artigoId,
    armazemId: dados.armazemId,
    lote: dados.lote?.trim() || undefined,
    dataValidade: dados.dataValidade || undefined,
    dataFabricacao: dados.dataFabricacao || undefined,
    quantidade,
    quantidadeReservada,
    quantidadeDisponivel: calcularQuantidadeDisponivel(quantidade, quantidadeReservada),
    custoUnitario,
    fornecedorId: dados.fornecedorId,
    documentoCompraId: dados.documentoCompraId,
    localizacao: dados.localizacao,
    status,
    criadoEm: agora,
    atualizadoEm: agora,
  };

  await salvarLote(novo);
  return novo;
}
export async function listarLotesFEFO(
  empresaId: string,
  artigoId: string,
  armazemId?: string,
): Promise<StockLote[]> {
  return await listarLotes(empresaId, {
    artigoId,
    armazemId,
    incluirExpirados: true,
    somenteDisponivel: true,
  });
}

export async function sugerirProximoLote(
  empresaId: string,
  artigoId: string,
  artigoCodigo?: string,
): Promise<string> {
  const lotes = await listarLotes(empresaId, {
    artigoId,
    incluirExpirados: true,
  });

  const codigoBase = (artigoCodigo?.trim().toUpperCase() || "LOTE")
    .replace(/\s+/g, "-")
    .replace(/[^A-Z0-9_-]/g, "");

  const prefixo = `${codigoBase}-`;
  let maiorSequencia = 0;

  for (const lote of lotes) {
    const valor = lote.lote?.trim().toUpperCase();
    if (!valor) continue;

    if (valor.startsWith(prefixo)) {
      const sufixo = valor.slice(prefixo.length);
      if (/^\d+$/.test(sufixo)) {
        maiorSequencia = Math.max(maiorSequencia, Number.parseInt(sufixo, 10));
        continue;
      }
    }

    const correspondenciaFinal = valor.match(/-(\d{1,6})$/);
    if (correspondenciaFinal) {
      maiorSequencia = Math.max(maiorSequencia, Number.parseInt(correspondenciaFinal[1], 10));
    }
  }

  return `${codigoBase}-${String(maiorSequencia + 1).padStart(3, "0")}`;
}

export async function planearConsumoPorLotes(
  empresaId: string,
  artigoId: string,
  quantidade: number,
  armazemId?: string,
  opcoes?: {
    incluirExpirados?: boolean;
    metodoCusteio?: MetodoCusteioStock;
  },
): Promise<ResultadoPlanoConsumoFEFO> {
  const lotes = await listarLotes(empresaId, {
    artigoId,
    armazemId,
    incluirExpirados: true,
    somenteDisponivel: false,
  });

  if (lotes.length === 0) {
    return {
      success: true,
      temLotes: false,
      plano: [],
      quantidadePlaneada: 0,
    };
  }

  const lotesConsumiveis = ordenarLotesPorMetodo(
    lotes.filter((lote) =>
      lote.quantidadeDisponivel > 0 &&
      (opcoes?.incluirExpirados || lote.status !== "expirado") &&
      lote.status !== "bloqueado",
    ),
    opcoes?.metodoCusteio,
  );

  let restante = quantidade;
  const plano: PlanoConsumoLote[] = [];

  for (const lote of lotesConsumiveis) {
    if (restante <= 0) break;

    const quantidadeConsumida = Math.min(restante, lote.quantidadeDisponivel);
    if (quantidadeConsumida <= 0) continue;

    plano.push({
      loteId: lote.id,
      artigoId: lote.artigoId,
      armazemId: lote.armazemId,
      lote: lote.lote,
      dataValidade: lote.dataValidade,
      quantidade: quantidadeConsumida,
    });

    restante -= quantidadeConsumida;
  }

  if (restante > 0) {
    const disponivel = quantidade - restante;
    return {
      success: false,
      temLotes: true,
      plano,
      quantidadePlaneada: disponivel,
      error: `Stock insuficiente em lotes consumiveis. Disponivel: ${disponivel}, solicitado: ${quantidade}`,
    };
  }

  return {
    success: true,
    temLotes: true,
    plano,
    quantidadePlaneada: quantidade,
  };
}

export async function planearConsumoFEFO(
  empresaId: string,
  artigoId: string,
  quantidade: number,
  armazemId?: string,
): Promise<ResultadoPlanoConsumoFEFO> {
  return planearConsumoPorLotes(
    empresaId,
    artigoId,
    quantidade,
    armazemId,
    { incluirExpirados: false },
  );
}

export async function planearConsumoLoteEspecifico(
  empresaId: string,
  artigoId: string,
  loteId: string,
  quantidade: number,
  armazemId?: string,
): Promise<ResultadoPlanoConsumoLote> {
  const lote = await buscarLotePorId(loteId);

  if (!lote || lote.empresaId !== empresaId) {
    return { success: false, error: "Lote não encontrado" };
  }

  if (lote.artigoId !== artigoId) {
    return { success: false, error: "O lote selecionado não pertence ao artigo informado" };
  }

  if (armazemId && lote.armazemId !== armazemId) {
    return { success: false, error: "O lote selecionado não pertence ao armazém informado" };
  }

  if (quantidade <= 0) {
    return { success: false, error: "Quantidade inválida para consumo do lote" };
  }

  if (lote.quantidadeDisponivel < quantidade) {
    return {
      success: false,
      error: `Lote ${lote.lote || lote.id} sem disponibilidade suficiente. Disponível: ${lote.quantidadeDisponivel}, solicitado: ${quantidade}`,
    };
  }

  return {
    success: true,
    plano: {
      loteId: lote.id,
      artigoId: lote.artigoId,
      armazemId: lote.armazemId,
      lote: lote.lote,
      dataValidade: lote.dataValidade,
      quantidade,
    },
  };
}

export async function aplicarPlanoConsumoFEFO(plano: PlanoConsumoLote[]): Promise<{ success: boolean; error?: string }> {
  const atualizacoes: StockLote[] = [];

  for (const item of plano) {
    if (!Number.isFinite(item.quantidade) || item.quantidade <= 0) {
      return { success: false, error: "Quantidade invalida no plano FEFO" };
    }

    const loteAtual = await buscarLotePorId(item.loteId);

    if (!loteAtual) {
      return { success: false, error: `Lote ${item.loteId} nao encontrado` };
    }

    if (loteAtual.quantidadeDisponivel < item.quantidade) {
      return {
        success: false,
        error: `Lote ${loteAtual.lote || loteAtual.id} sem disponibilidade suficiente. Disponivel: ${loteAtual.quantidadeDisponivel}, solicitado: ${item.quantidade}`,
      };
    }

    const novaQuantidade = loteAtual.quantidade - item.quantidade;
    const erroSaldo = validarSaldoLote(novaQuantidade, loteAtual.quantidadeReservada);
    if (erroSaldo) {
      return { success: false, error: erroSaldo };
    }

    atualizacoes.push({
      ...loteAtual,
      quantidade: novaQuantidade,
      quantidadeDisponivel: calcularQuantidadeDisponivel(novaQuantidade, loteAtual.quantidadeReservada),
      status: calcularStatus(loteAtual.dataValidade, loteAtual.status),
      atualizadoEm: new Date().toISOString(),
    });
  }

  for (const lote of atualizacoes) {
    await salvarLote(lote);
  }

  return { success: true };
}

export async function reporPlanoConsumoFEFO(plano: PlanoConsumoLote[]): Promise<void> {
  for (const item of plano) {
    if (!Number.isFinite(item.quantidade) || item.quantidade <= 0) continue;

    const loteAtual = await buscarLotePorId(item.loteId);
    if (!loteAtual) continue;

    const novaQuantidade = loteAtual.quantidade + item.quantidade;
    const erroSaldo = validarSaldoLote(novaQuantidade, loteAtual.quantidadeReservada);
    if (erroSaldo) {
      throw new Error(erroSaldo);
    }

    await salvarLote({
      ...loteAtual,
      quantidade: novaQuantidade,
      quantidadeDisponivel: calcularQuantidadeDisponivel(novaQuantidade, loteAtual.quantidadeReservada),
      status: calcularStatus(loteAtual.dataValidade, loteAtual.status),
      atualizadoEm: new Date().toISOString(),
    });
  }
}
export async function transferirLoteEntreArmazens(dados: {
  empresaId: string;
  loteId: string;
  armazemDestinoId: string;
  quantidade: number;
}): Promise<ResultadoTransferenciaLote> {
  const loteOrigemAtual = await buscarLotePorId(dados.loteId);

  if (!loteOrigemAtual || loteOrigemAtual.empresaId !== dados.empresaId) {
    return { success: false, error: "Lote nao encontrado" };
  }

  if (loteOrigemAtual.armazemId === dados.armazemDestinoId) {
    return { success: false, error: "O lote ja esta no armazem de destino" };
  }

  if (!Number.isFinite(dados.quantidade) || dados.quantidade <= 0) {
    return { success: false, error: "Quantidade invalida para transferencia do lote" };
  }

  if (loteOrigemAtual.quantidadeDisponivel < dados.quantidade) {
    return {
      success: false,
      error: `Lote ${loteOrigemAtual.lote || loteOrigemAtual.id} sem disponibilidade suficiente. Disponivel: ${loteOrigemAtual.quantidadeDisponivel}, solicitado: ${dados.quantidade}`,
    };
  }

  const destinoExistente = await buscarLotePorIdentidade(
    dados.empresaId,
    loteOrigemAtual.artigoId,
    dados.armazemDestinoId,
    loteOrigemAtual.lote,
    loteOrigemAtual.dataValidade,
  );

  const stockOrigemAnterior = await stockArmazem.buscarStockArtigoArmazem(
    dados.empresaId,
    loteOrigemAtual.artigoId,
    loteOrigemAtual.armazemId,
  );
  const stockDestinoAnterior = await stockArmazem.buscarStockArtigoArmazem(
    dados.empresaId,
    loteOrigemAtual.artigoId,
    dados.armazemDestinoId,
  );

  const quantidadeOrigemAnterior = loteOrigemAtual.quantidade;
  const quantidadeDestinoAnterior = destinoExistente?.quantidade || 0;
  const novaQuantidadeOrigem = loteOrigemAtual.quantidade - dados.quantidade;
  const erroOrigem = validarSaldoLote(novaQuantidadeOrigem, loteOrigemAtual.quantidadeReservada);
  if (erroOrigem) {
    return { success: false, error: erroOrigem };
  }

  const loteOrigemAtualizado: StockLote = {
    ...loteOrigemAtual,
    quantidade: novaQuantidadeOrigem,
    quantidadeDisponivel: calcularQuantidadeDisponivel(novaQuantidadeOrigem, loteOrigemAtual.quantidadeReservada),
    status: calcularStatus(loteOrigemAtual.dataValidade, loteOrigemAtual.status),
    atualizadoEm: new Date().toISOString(),
  };

  let loteDestinoAtualizado: StockLote | null = null;
  let origemStockAtualizado = false;
  let destinoStockAtualizado = false;

  await salvarLote(loteOrigemAtualizado);

  try {
    loteDestinoAtualizado = await upsertLote({
      empresaId: dados.empresaId,
      artigoId: loteOrigemAtual.artigoId,
      armazemId: dados.armazemDestinoId,
      lote: loteOrigemAtual.lote,
      dataValidade: loteOrigemAtual.dataValidade,
      dataFabricacao: loteOrigemAtual.dataFabricacao,
      quantidade: quantidadeDestinoAnterior + dados.quantidade,
      quantidadeReservada: destinoExistente?.quantidadeReservada || 0,
      custoUnitario: loteOrigemAtual.custoUnitario,
      fornecedorId: loteOrigemAtual.fornecedorId,
      documentoCompraId: loteOrigemAtual.documentoCompraId,
      localizacao: destinoExistente?.localizacao || loteOrigemAtual.localizacao,
      status: loteOrigemAtual.status,
    });

    const origemStock = await stockArmazem.atualizarStockArmazem({
      empresaId: dados.empresaId,
      armazemId: loteOrigemAtual.armazemId,
      armazemCodigo: "",
      armazemNome: "",
      artigoId: loteOrigemAtual.artigoId,
      artigoCodigo: "",
      artigoNome: "",
      quantidadeDelta: -dados.quantidade,
    });

    if (!origemStock.success) {
      throw new Error(origemStock.error || "Erro ao atualizar stock do armazem de origem");
    }
    origemStockAtualizado = true;

    const destinoStock = await stockArmazem.atualizarStockArmazem({
      empresaId: dados.empresaId,
      armazemId: dados.armazemDestinoId,
      armazemCodigo: "",
      armazemNome: "",
      artigoId: loteOrigemAtual.artigoId,
      artigoCodigo: "",
      artigoNome: "",
      quantidadeDelta: dados.quantidade,
    });

    if (!destinoStock.success) {
      throw new Error(destinoStock.error || "Erro ao atualizar stock do armazem de destino");
    }
    destinoStockAtualizado = true;

    return {
      success: true,
      loteOrigem: loteOrigemAtualizado,
      loteDestino: loteDestinoAtualizado,
    };
  } catch (error) {
    await salvarLote({
      ...loteOrigemAtual,
      quantidade: quantidadeOrigemAnterior,
      quantidadeDisponivel: loteOrigemAtual.quantidadeDisponivel,
      atualizadoEm: new Date().toISOString(),
    });

    if (destinoExistente) {
      await salvarLote({
        ...destinoExistente,
        quantidade: quantidadeDestinoAnterior,
        quantidadeDisponivel: calcularQuantidadeDisponivel(quantidadeDestinoAnterior, destinoExistente.quantidadeReservada),
        atualizadoEm: new Date().toISOString(),
      });
    } else if (loteDestinoAtualizado) {
      await deletarLote(loteDestinoAtualizado.id);
    }

    if (origemStockAtualizado && stockOrigemAnterior) {
      await stockArmazem.upsertStock({
        empresaId: dados.empresaId,
        artigoId: loteOrigemAtual.artigoId,
        armazemId: loteOrigemAtual.armazemId,
        quantidade: stockOrigemAnterior.quantidade,
        quantidadeReservada: stockOrigemAnterior.quantidadeReservada,
        custoMedio: stockOrigemAnterior.custoMedio,
        localizacao: stockOrigemAnterior.localizacao,
        lote: stockOrigemAnterior.lote,
        dataValidade: stockOrigemAnterior.dataValidade,
      });
    }

    if (destinoStockAtualizado) {
      if (stockDestinoAnterior) {
        await stockArmazem.upsertStock({
          empresaId: dados.empresaId,
          artigoId: loteOrigemAtual.artigoId,
          armazemId: dados.armazemDestinoId,
          quantidade: stockDestinoAnterior.quantidade,
          quantidadeReservada: stockDestinoAnterior.quantidadeReservada,
          custoMedio: stockDestinoAnterior.custoMedio,
          localizacao: stockDestinoAnterior.localizacao,
          lote: stockDestinoAnterior.lote,
          dataValidade: stockDestinoAnterior.dataValidade,
        });
      } else {
        const stockDestinoCriado = await stockArmazem.buscarStockArtigoArmazem(
          dados.empresaId,
          loteOrigemAtual.artigoId,
          dados.armazemDestinoId,
        );
        if (stockDestinoCriado) {
          await stockArmazem.deletarStock(stockDestinoCriado.id);
        }
      }
    }

    return {
      success: false,
      error: error instanceof Error ? error.message : "Erro ao transferir lote entre armazens",
    };
  }
}
export async function obterResumoLotesArtigo(empresaId: string, artigoId: string): Promise<ResumoLoteArtigo> {
  const config = await obterConfiguracaoPosValidade(empresaId);
  const lotes = await listarLotes(empresaId, {
    artigoId,
    incluirExpirados: true,
  });

  const lotesDisponiveis = lotes.filter((lote) => lote.quantidadeDisponivel > 0);
  const lotesValidos = lotesDisponiveis.filter((lote) => lote.status !== "expirado");
  const proximaValidade = lotesValidos
    .filter((lote) => !!lote.dataValidade)
    .sort((a, b) => (a.dataValidade || "").localeCompare(b.dataValidade || ""))[0]?.dataValidade;
  const diasParaProximaValidade = calcularDiasParaValidade(proximaValidade);

  return {
    artigoId,
    totalLotes: lotes.length,
    quantidadeTotal: lotes.reduce((sum, lote) => sum + lote.quantidade, 0),
    quantidadeDisponivel: lotesDisponiveis.reduce((sum, lote) => sum + lote.quantidadeDisponivel, 0),
    quantidadeDisponivelValida: lotesValidos.reduce((sum, lote) => sum + lote.quantidadeDisponivel, 0),
    quantidadeExpirada: lotesDisponiveis
      .filter((lote) => lote.status === "expirado")
      .reduce((sum, lote) => sum + lote.quantidadeDisponivel, 0),
    proximaValidade,
    diasParaProximaValidade,
    nivelAlertaValidade: lotesValidos.length > 0
      ? obterNivelAlertaValidade(diasParaProximaValidade, config)
      : (lotesDisponiveis.some((lote) => lote.status === "expirado") ? "expirado" : "normal"),
    alertaValidade: lotesValidos.length > 0
      ? obterMensagemAlertaValidade(diasParaProximaValidade)
      : (lotesDisponiveis.some((lote) => lote.status === "expirado") ? "Produto expirado" : undefined),
    descontoValidadeSugerido: lotesValidos.length > 0
      ? obterDescontoSugeridoValidade(diasParaProximaValidade, config)
      : 0,
    temLotes: lotes.length > 0,
  };
}

export async function obterMapaResumoArtigos(
  empresaId: string,
  artigosIds: string[],
): Promise<Record<string, ResumoLoteArtigo>> {
  const config = await obterConfiguracaoPosValidade(empresaId);
  const lotes = await listarLotesPorEmpresa(empresaId);
  const ids = new Set(artigosIds);
  const mapa: Record<string, ResumoLoteArtigo> = {};

  for (const artigoId of artigosIds) {
    mapa[artigoId] = {
      artigoId,
      totalLotes: 0,
      quantidadeTotal: 0,
      quantidadeDisponivel: 0,
      quantidadeDisponivelValida: 0,
      quantidadeExpirada: 0,
      proximaValidade: undefined,
      diasParaProximaValidade: undefined,
      nivelAlertaValidade: "normal",
      alertaValidade: undefined,
      descontoValidadeSugerido: 0,
      temLotes: false,
    };
  }

  for (const lote of lotes) {
    if (!ids.has(lote.artigoId)) continue;

    const resumo = mapa[lote.artigoId];
    resumo.totalLotes += 1;
    resumo.temLotes = true;
    resumo.quantidadeTotal += lote.quantidade;

    if (lote.quantidadeDisponivel > 0) {
      resumo.quantidadeDisponivel += lote.quantidadeDisponivel;
      if (lote.status === "expirado") {
        resumo.quantidadeExpirada += lote.quantidadeDisponivel;
      } else {
        resumo.quantidadeDisponivelValida += lote.quantidadeDisponivel;
      }
    }

    if (lote.status !== "expirado" && lote.dataValidade) {
      if (!resumo.proximaValidade || lote.dataValidade < resumo.proximaValidade) {
        resumo.proximaValidade = lote.dataValidade;
      }
    }
  }

  for (const artigoId of artigosIds) {
    const resumo = mapa[artigoId];
    resumo.diasParaProximaValidade = calcularDiasParaValidade(resumo.proximaValidade);

    if (resumo.quantidadeDisponivelValida > 0) {
      resumo.nivelAlertaValidade = obterNivelAlertaValidade(resumo.diasParaProximaValidade, config);
      resumo.alertaValidade = obterMensagemAlertaValidade(resumo.diasParaProximaValidade);
      resumo.descontoValidadeSugerido = obterDescontoSugeridoValidade(resumo.diasParaProximaValidade, config);
    } else if (resumo.quantidadeExpirada > 0) {
      resumo.nivelAlertaValidade = "expirado";
      resumo.alertaValidade = "Produto expirado";
      resumo.descontoValidadeSugerido = 0;
    }
  }

  return mapa;
}

export async function listarAlertasValidade(
  empresaId: string,
  diasLimite = 30,
): Promise<AlertaValidadeLote[]> {
  const config = await obterConfiguracaoPosValidade(empresaId);
  const lotes = await listarLotes(empresaId, { incluirExpirados: true, somenteDisponivel: true });

  return lotes
    .filter((lote) => !!lote.dataValidade)
    .map((lote) => {
      const diasParaValidade = calcularDiasParaValidade(lote.dataValidade) ?? 0;
      return {
        ...lote,
        diasParaValidade,
        nivelAlerta: obterNivelAlertaValidade(diasParaValidade, config),
        alerta: obterMensagemAlertaValidade(diasParaValidade) || "Validade monitorada",
        descontoSugerido: lote.status === "expirado" ? 0 : obterDescontoSugeridoValidade(diasParaValidade, config),
      };
    })
    .filter((lote) => lote.diasParaValidade <= Math.min(diasLimite, config.diasMonitorizacao))
    .sort((a, b) => a.diasParaValidade - b.diasParaValidade);
}

