import * as kv from "./kv_store.tsx";
import { obterSubscricao } from "./subscricoes.tsx";

// Tipos de movimentos financeiros
export type TipoMovimento = "inscricao" | "avenca" | "ajuste" | "credito" | "estorno";
export type MetodoPagamento = "transferencia" | "deposito" | "mpesa" | "emola" | "dinheiro" | "cheque";
export type StatusPagamento = "pendente" | "pago" | "atrasado" | "cancelado";

// Movimento financeiro (débito ou crédito)
export type MovimentoFinanceiro = {
  id: string;
  empresaId: string;
  tipo: TipoMovimento;
  descricao: string;
  valor: number; // Positivo para crédito, negativo para débito
  dataMovimento: string;
  dataPagamento?: string;
  proximaDataPagamento?: string; // Próxima data de vencimento
  metodoPagamento?: MetodoPagamento;
  numeroDocumento?: string; // Número da fatura, recibo, etc.
  comprovante?: string; // URL do comprovante
  status: StatusPagamento;
  observacoes?: string;
  detalhes?: Record<string, unknown>;
  criadoPor?: string;
  dataCriacao: string;
};

// Resumo da conta corrente
export type ContaCorrente = {
  empresaId: string;
  totalDebitos: number;
  totalCreditos: number;
  saldo: number; // Negativo = deve, Positivo = crédito
  ultimoPagamento?: string;
  proximoVencimento?: string;
  statusPagamento: "em-dia" | "pendente" | "atrasado";
  diasEmAtraso?: number; // NOVO: adicionar dias em atraso
};

// ========== PREFIXOS ÚNICOS ==========
const MOVIMENTOS_PREFIX = "movimento_financeiro:";
const CONTA_CORRENTE_PREFIX = "conta_corrente:";

/**
 * Gerar ID único para movimento
 */
function gerarIdMovimento(): string {
  return `mov_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}

/**
 * Registrar movimento financeiro
 */
export async function registrarMovimento(
  dados: Omit<MovimentoFinanceiro, "id" | "dataCriacao">
): Promise<{ success: boolean; data?: MovimentoFinanceiro; error?: string }> {
  try {
    // Validações
    if (!dados.empresaId) {
      return { success: false, error: "ID da empresa é obrigatório" };
    }

    if (!dados.valor || dados.valor === 0) {
      return { success: false, error: "Valor é obrigatório" };
    }

    if (!dados.descricao) {
      return { success: false, error: "Descrição é obrigatória" };
    }

    const id = gerarIdMovimento();
    const agora = new Date().toISOString();

    // ✅ id depois do spread de ...dados: impede que um id vindo do
    // cliente (ex.: POST /admin/pagamentos, que passa o body bruto direto
    // para esta função) sobreponha o id gerado no servidor — mesma
    // correcção já aplicada em clientes.tsx/fornecedores.tsx/compras.tsx.
    const movimento: MovimentoFinanceiro = {
      ...dados,
      id,
      dataCriacao: agora,
    };

    // Salvar movimento
    await kv.set(`${MOVIMENTOS_PREFIX}${id}`, movimento);

    // Atualizar conta corrente
    await atualizarContaCorrente(dados.empresaId);

    // console.log(`[PAGAMENTOS] Movimento registrado: ${id} - ${dados.descricao}`);

    return { success: true, data: movimento };
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao registrar movimento:", error);
    return { success: false, error: `Erro ao registrar movimento: ${error.message}` };
  }
}

/**
 * Listar movimentos de uma empresa
 */
export async function listarMovimentosEmpresa(empresaId: string): Promise<MovimentoFinanceiro[]> {
  try {
    const resultados = await kv.getByPrefix(MOVIMENTOS_PREFIX);
    
    // CORREÇÃO: getByPrefix retorna valores DIRETAMENTE
    const movimentos = resultados
      .filter((m: any) => m && m.empresaId === empresaId);
    
    return (movimentos as MovimentoFinanceiro[])
      .sort((a, b) => new Date(b.dataMovimento).getTime() - new Date(a.dataMovimento).getTime());
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao listar movimentos:", error);
    return [];
  }
}

/**
 * Buscar movimento por ID
 */
export async function buscarMovimento(id: string): Promise<MovimentoFinanceiro | null> {
  try {
    const movimento = await kv.get(`${MOVIMENTOS_PREFIX}${id}`);
    return movimento as MovimentoFinanceiro | null;
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao buscar movimento:", error);
    return null;
  }
}

/**
 * Atualizar status de pagamento
 */
export async function atualizarStatusPagamento(
  id: string,
  status: StatusPagamento,
  dataPagamento?: string
): Promise<{ success: boolean; error?: string }> {
  try {
    const movimento = await buscarMovimento(id);
    if (!movimento) {
      return { success: false, error: "Movimento não encontrado" };
    }

    movimento.status = status;
    if (dataPagamento) {
      movimento.dataPagamento = dataPagamento;
    }

    await kv.set(`${MOVIMENTOS_PREFIX}${id}`, movimento);
    await atualizarContaCorrente(movimento.empresaId);

    // console.log(`[PAGAMENTOS] Status atualizado: ${id} - ${status}`);

    return { success: true };
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao atualizar status:", error);
    return { success: false, error: `Erro ao atualizar status: ${error.message}` };
  }
}

/**
 * Calcular e atualizar conta corrente da empresa
 */
export async function atualizarContaCorrente(empresaId: string): Promise<ContaCorrente> {
  try {
    const movimentos = await listarMovimentosEmpresa(empresaId);
    // Considerar APENAS movimentos PAGOS para o cálculo
    const movimentosPagos = movimentos.filter((m) => m.status === "pago");

    const totalDebitos = movimentosPagos
      .filter((m) => m.valor < 0)
      .reduce((acc, m) => acc + Math.abs(m.valor), 0);

    const totalCreditos = movimentosPagos
      .filter((m) => m.valor > 0)
      .reduce((acc, m) => acc + m.valor, 0);

    const saldo = totalCreditos - totalDebitos;

    // Encontrar último pagamento
    const ultimoPagamentoMov = movimentosPagos
      .filter((m) => m.valor > 0 && m.dataPagamento)
      .sort((a, b) => new Date(b.dataPagamento!).getTime() - new Date(a.dataPagamento!).getTime())[0];

    const ultimoPagamento = ultimoPagamentoMov?.dataPagamento;

    // Encontrar próximo vencimento (movimento mais recente com proximaDataPagamento)
    const movimentoComProximaData = movimentosPagos
      .filter((m) => m.proximaDataPagamento)
      .sort((a, b) => new Date(b.dataMovimento).getTime() - new Date(a.dataMovimento).getTime())[0];
    
    const proximoVencimento = movimentoComProximaData?.proximaDataPagamento;

    // Determinar status de pagamento e calcular dias em atraso
    let statusPagamento: "em-dia" | "pendente" | "atrasado" = "em-dia";
    let diasEmAtraso = 0;
    
    if (proximoVencimento) {
      const hoje = new Date();
      hoje.setHours(0, 0, 0, 0); // Zerar horas para comparação precisa
      
      const dataVencimento = new Date(proximoVencimento);
      dataVencimento.setHours(0, 0, 0, 0);
      
      const diasAteVencimento = Math.floor((dataVencimento.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24));
      
      if (diasAteVencimento < 0) {
        // ATRASADO: passou a data de vencimento
        statusPagamento = "atrasado";
        diasEmAtraso = Math.abs(diasAteVencimento);
      } else {
        // PAGO/EM DIA: ainda não venceu
        statusPagamento = "em-dia";
        diasEmAtraso = 0;
      }
    }

    const contaCorrente: ContaCorrente = {
      empresaId,
      totalDebitos,
      totalCreditos,
      saldo,
      ultimoPagamento,
      proximoVencimento,
      statusPagamento,
      diasEmAtraso, // NOVO: adicionar dias em atraso
    };

    await kv.set(`${CONTA_CORRENTE_PREFIX}${empresaId}`, contaCorrente);

    return contaCorrente;
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao atualizar conta corrente:", error);
    throw error;
  }
}

/**
 * Obter conta corrente de uma empresa
 */
export async function obterContaCorrente(empresaId: string): Promise<ContaCorrente | null> {
  try {
    let contaCorrente = await kv.get(`${CONTA_CORRENTE_PREFIX}${empresaId}`);
    
    if (!contaCorrente) {
      // Se não existe, calcular
      contaCorrente = await atualizarContaCorrente(empresaId);
    }

    return contaCorrente as ContaCorrente;
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao obter conta corrente:", error);
    return null;
  }
}

/**
 * Registrar pagamento de avença
 */
export async function registrarPagamentoAvenca(
  empresaId: string,
  valor: number,
  mesReferencia: string,
  metodoPagamento: MetodoPagamento,
  numeroDocumento?: string,
  comprovante?: string,
  observacoes?: string,
  cicloMeses: number = 1,
  detalhes?: Record<string, unknown>
): Promise<{ success: boolean; data?: MovimentoFinanceiro; error?: string }> {
  // ✅ Estender a partir do vencimento actual da subscricao quando ainda nao
  // passou (em vez de sempre "hoje + ciclo"), para bater com o calculo real
  // usado por subscricoes.registrarRenovacao — evita que pagar adiantado
  // faca o "proximo vencimento" mostrado na conta-corrente parecer mais
  // cedo do que a data real que controla o acesso aos modulos.
  const hoje = new Date();
  const subscricaoActual = await obterSubscricao(empresaId).catch(() => null);
  const vencimentoActual = subscricaoActual ? new Date(subscricaoActual.dataProximaRenovacao) : null;
  const baseProximaData =
    vencimentoActual && !Number.isNaN(vencimentoActual.getTime()) && vencimentoActual > hoje
      ? vencimentoActual
      : hoje;
  const proximaData = new Date(baseProximaData);
  proximaData.setMonth(proximaData.getMonth() + cicloMeses);

  return await registrarMovimento({
    empresaId,
    tipo: "avenca",
    descricao: `Pagamento de Avença - ${mesReferencia}`,
    valor: valor, // Positivo = crédito
    dataMovimento: hoje.toISOString(),
    dataPagamento: hoje.toISOString(),
    proximaDataPagamento: proximaData.toISOString(), // Próximo vencimento
    metodoPagamento,
    numeroDocumento,
    comprovante,
    status: "pago", // JÁ PAGO quando registra
    observacoes,
    detalhes,
  });
}

/**
 * Registrar taxa de inscrição
 */
export async function registrarTaxaInscricao(
  empresaId: string,
  valor: number,
  metodoPagamento: MetodoPagamento,
  numeroDocumento?: string,
  comprovante?: string,
  observacoes?: string,
  detalhes?: Record<string, unknown>
): Promise<{ success: boolean; data?: MovimentoFinanceiro; error?: string }> {
  return await registrarMovimento({
    empresaId,
    tipo: "inscricao",
    descricao: "Taxa de Inscrição",
    valor: valor, // Positivo = crédito
    dataMovimento: new Date().toISOString(),
    dataPagamento: new Date().toISOString(),
    metodoPagamento,
    numeroDocumento,
    comprovante,
    status: "pago",
    observacoes,
    detalhes,
  });
}

/**
 * Gerar débito mensal de avença
 */
export async function gerarDebitoAvenca(
  empresaId: string,
  valorAvenca: number,
  mesReferencia: string
): Promise<{ success: boolean; data?: MovimentoFinanceiro; error?: string }> {
  return await registrarMovimento({
    empresaId,
    tipo: "avenca",
    descricao: `Avença Mensal - ${mesReferencia}`,
    valor: -valorAvenca, // Negativo = débito
    dataMovimento: new Date().toISOString(),
    status: "pendente",
    observacoes: `Débito automático de avença para o mês ${mesReferencia}`,
  });
}

/**
 * Cancelar/Estornar movimento
 */
export async function cancelarMovimento(
  id: string,
  motivo: string
): Promise<{ success: boolean; error?: string }> {
  try {
    const movimento = await buscarMovimento(id);
    if (!movimento) {
      return { success: false, error: "Movimento não encontrado" };
    }

    movimento.status = "cancelado";
    movimento.observacoes = `${movimento.observacoes || ""}\nCANCELADO: ${motivo}`;

    await kv.set(`${MOVIMENTOS_PREFIX}${id}`, movimento);
    await atualizarContaCorrente(movimento.empresaId);

    // console.log(`[PAGAMENTOS] Movimento cancelado: ${id}`);

    return { success: true };
  } catch (error) {
    // console.error("[PAGAMENTOS] Erro ao cancelar movimento:", error);
    return { success: false, error: `Erro ao cancelar movimento: ${error.message}` };
  }
}
