import * as kv from "./kv_store.tsx";
import * as empresasModule from "./empresas.tsx";
import {
  PlanoId,
  obterPlanoConfiguradoPorId,
  obterPlanosCompatibilidadeConfigurados,
} from "./modulos.tsx";
import {
  DEFAULT_POLITICA_SUBSCRICAO,
  obterPoliticaSubscricao,
  type PoliticaSubscricao,
} from "./tonline-config.tsx";

// ========== TIPOS ==========

/**
 * Estados do ciclo de vida de uma subscrição
 */
export type EstadoSubscricao =
  | "TRIAL"              // Período de teste (futuro)
  | "ACTIVE"             // Ativa e em dia
  | "PENDING_PAYMENT"    // Pagamento pendente (dia do vencimento)
  | "GRACE_PERIOD"       // Dentro do período de tolerância
  | "SUSPENDED"          // Suspensa por falta de pagamento
  | "CANCELED";          // Cancelada pelo cliente

/**
 * Entidade de Subscrição (FONTE ÚNICA DE VERDADE)
 */
export type Subscricao = {
  id: string;
  empresaId: string;
  planoId: PlanoId;                    // ID do plano, não nome
  estado: EstadoSubscricao;
  
  // Datas
  dataInicio: string;
  dataProximaRenovacao: string;
  
  // Configurações
  diasGracePeriod: number;             // Dias de tolerância após vencimento
  gracePeriodHoras?: number;
  valorMensalAtual: number;            // Compatibilidade: valor recorrente do ciclo atual
  cicloMeses?: number;
  valorRecorrenteAtual?: number;
  taxaLicencaUnica?: number;
  licencaPaga?: boolean;

  // Mudança de plano agendada — já paga antecipadamente, mas só entra em
  // vigor em dataEfetivacaoAgendada (o fim do ciclo actual). Ver
  // agendarMudancaPlano() e a 4ª regra de processarRenovacoes().
  planoAgendadoId?: PlanoId;
  dataEfetivacaoAgendada?: string;
  pagamentoAgendadoMovimentoId?: string;

  // Histórico
  historicoRenovacoes: Renovacao[];
  historicoMudancas: MudancaEstado[];
  
  // Auditoria
  dataCriacao: string;
  dataUltimaAtualizacao: string;
};

/**
 * Registro de renovação (pagamento)
 */
export type Renovacao = {
  data: string;
  valorPago: number;
  metodoPagamento: string;
  proximaRenovacao: string;
  dataVencimentoAnterior?: string;
  periodoInicio?: string;
  periodoFim?: string;
  movimentoFinanceiroId?: string;      // Link para movimento em pagamentos
  observacoes?: string;
  snapshotPlano?: Record<string, unknown>;
};

/**
 * Registro de mudança de estado
 */
export type MudancaEstado = {
  data: string;
  estadoAnterior: EstadoSubscricao | null;
  estadoNovo: EstadoSubscricao;
  motivo: string;
  automatico: boolean;                 // true = mudança automática, false = manual
  usuarioId?: string;                  // ID do usuário que fez a mudança (se manual)
};

/**
 * Registro de mudança de plano
 */
export type MudancaPlano = {
  data: string;
  planoAnterior: PlanoId;
  planoNovo: PlanoId;
  motivo: string;
  usuarioId?: string;
};

// ========== CONSTANTES ==========

const SUBSCRICAO_PREFIX = "subscricao:";
const DIAS_GRACE_PERIOD_PADRAO = Math.ceil(DEFAULT_POLITICA_SUBSCRICAO.gracePeriodHoras / 24);

// ========== FUNÇÕES UTILITÁRIAS ==========

/**
 * Gerar ID único para subscrição
 */
function gerarIdSubscricao(): string {
  return `sub_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}

/**
 * Calcular próxima data de renovação (30 dias a partir de agora)
 */
async function obterPoliticaSegura(): Promise<PoliticaSubscricao> {
  try {
    return await obterPoliticaSubscricao();
  } catch (error) {
    console.error("[SUBSCRICOES] Erro ao obter politica de subscricao:", error);
    return DEFAULT_POLITICA_SUBSCRICAO;
  }
}

function calcularProximaRenovacao(
  dataBase?: Date,
  cicloMeses: number = 1,
  planoId?: PlanoId,
  politica: PoliticaSubscricao = DEFAULT_POLITICA_SUBSCRICAO,
): string {
  const base = dataBase || new Date();
  const proxima = new Date(base);

  if (planoId === "mensal" && politica.modoTesteMensal) {
    proxima.setMinutes(proxima.getMinutes() + politica.expiracaoMensalTesteMinutos);
    return proxima.toISOString();
  }

  proxima.setMonth(proxima.getMonth() + cicloMeses);
  return proxima.toISOString();
}

function calcularMinutosParaVencimento(dataRenovacao: Date, agora = new Date()): number {
  return Math.ceil((dataRenovacao.getTime() - agora.getTime()) / (1000 * 60));
}

function calcularValorMensalEquivalente(subscricao: Subscricao): number {
  const cicloMeses = subscricao.cicloMeses || 1;
  const valorRecorrente = subscricao.valorRecorrenteAtual || subscricao.valorMensalAtual || 0;
  return valorRecorrente / cicloMeses;
}

function obterGracePeriodHoras(
  subscricao: Subscricao,
  politica: PoliticaSubscricao = DEFAULT_POLITICA_SUBSCRICAO,
): number {
  const configuradoNaSubscricao = Number(subscricao.gracePeriodHoras);
  if (Number.isFinite(configuradoNaSubscricao) && configuradoNaSubscricao >= 0) {
    return configuradoNaSubscricao;
  }

  const configuradoGlobal = Number(politica.gracePeriodHoras);
  if (Number.isFinite(configuradoGlobal) && configuradoGlobal >= 0) {
    return configuradoGlobal;
  }

  return Math.max(0, Number(subscricao.diasGracePeriod || DIAS_GRACE_PERIOD_PADRAO) * 24);
}

// ========== FUNÇÕES CRUD ==========

/**
 * Criar nova subscrição ao aplicar plano
 */
export async function criarSubscricao(
  empresaId: string,
  planoId: PlanoId,
  opcoes?: {
    diasGracePeriod?: number;
    dataInicio?: string;
    licencaPaga?: boolean;
  }
): Promise<{ success: boolean; data?: Subscricao; error?: string }> {
  try {
    console.log(`[SUBSCRICOES] 🆕 Criando subscrição para empresa ${empresaId}, plano ${planoId}`);
    
    // Verificar se já existe subscrição
    const existente = await obterSubscricao(empresaId);
    if (existente) {
      console.log(`[SUBSCRICOES] ⚠️ Empresa já possui subscrição: ${existente.id}`);
      return { 
        success: false, 
        error: "Empresa já possui subscrição ativa. Use a função de mudança de plano para alterar." 
      };
    }
    
    // Buscar dados do plano
    const plano = await obterPlanoConfiguradoPorId(planoId);
    if (!plano) {
      console.error(`[SUBSCRICOES] ❌ Plano não encontrado: ${planoId}`);
      return { success: false, error: `Plano '${planoId}' não encontrado` };
    }
    
    const agora = new Date();
    const politica = await obterPoliticaSegura();
    const dataInicio = opcoes?.dataInicio || agora.toISOString();
    const cicloMeses = plano.cicloMeses || 1;
    const gracePeriodHoras = Number(opcoes?.diasGracePeriod) > 0
      ? Number(opcoes?.diasGracePeriod) * 24
      : politica.gracePeriodHoras;
    const proximaRenovacao = calcularProximaRenovacao(new Date(dataInicio), cicloMeses, plano.id, politica);
    
    const subscricao: Subscricao = {
      id: gerarIdSubscricao(),
      empresaId,
      planoId,
      estado: "ACTIVE",
      dataInicio,
      dataProximaRenovacao: proximaRenovacao,
      diasGracePeriod: Math.ceil(gracePeriodHoras / 24) || DIAS_GRACE_PERIOD_PADRAO,
      gracePeriodHoras,
      valorMensalAtual: plano.avencaTotal,
      cicloMeses,
      valorRecorrenteAtual: plano.avencaTotal,
      taxaLicencaUnica: plano.taxaInscricaoTotal,
      licencaPaga: opcoes?.licencaPaga || false,
      historicoRenovacoes: [],
      historicoMudancas: [{
        data: agora.toISOString(),
        estadoAnterior: null,
        estadoNovo: "ACTIVE",
        motivo: `Subscrição inicial ao plano ${plano.nome}`,
        automatico: false,
      }],
      dataCriacao: agora.toISOString(),
      dataUltimaAtualizacao: agora.toISOString(),
    };
    
    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);
    
    console.log(`[SUBSCRICOES] ✅ Subscrição criada: ${subscricao.id}`);
    console.log(`[SUBSCRICOES] - Plano: ${plano.nome}`);
    console.log(`[SUBSCRICOES] - Valor recorrente: ${subscricao.valorMensalAtual} MZN`);
    console.log(`[SUBSCRICOES] - Próxima renovação: ${subscricao.dataProximaRenovacao}`);
    
    return { success: true, data: subscricao };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao criar subscrição:`, error);
    return { success: false, error: `Erro ao criar subscrição: ${error.message}` };
  }
}

/**
 * Obter subscrição de uma empresa
 */
export async function obterSubscricao(empresaId: string): Promise<Subscricao | null> {
  try {
    const subscricao = await kv.get(`${SUBSCRICAO_PREFIX}${empresaId}`);
    return subscricao as Subscricao | null;
  } catch (error) {
    console.error(`[SUBSCRICOES] Erro ao obter subscrição:`, error);
    return null;
  }
}

/**
 * Listar todas as subscrições (para processos batch)
 */
export async function listarTodasSubscricoes(): Promise<Subscricao[]> {
  try {
    const resultados = await kv.getByPrefix(SUBSCRICAO_PREFIX);
    return resultados.filter((s: any) => s !== null && s !== undefined) as Subscricao[];
  } catch (error) {
    console.error(`[SUBSCRICOES] Erro ao listar subscrições:`, error);
    return [];
  }
}

/**
 * Atualizar estado da subscrição
 */
export async function atualizarEstadoSubscricao(
  empresaId: string,
  novoEstado: EstadoSubscricao,
  dados: {
    motivo: string;
    automatico?: boolean;
    usuarioId?: string;
  }
): Promise<{
  success: boolean;
  data?: {
    subscricao: Subscricao;
    estadoAnterior: EstadoSubscricao;
    estadoNovo: EstadoSubscricao;
  };
  error?: string;
}> {
  try {
    console.log(`[SUBSCRICOES] 🔄 Atualizando estado - Empresa: ${empresaId}, Novo estado: ${novoEstado}`);
    
    const subscricao = await obterSubscricao(empresaId);
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    
    const estadoAnterior = subscricao.estado;
    
    // Adicionar mudança ao histórico
    subscricao.historicoMudancas.push({
      data: new Date().toISOString(),
      estadoAnterior,
      estadoNovo: novoEstado,
      motivo: dados.motivo,
      automatico: dados.automatico !== false, // Padrão: true
      usuarioId: dados.usuarioId,
    });
    
    subscricao.estado = novoEstado;
    subscricao.dataUltimaAtualizacao = new Date().toISOString();
    
    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);
    
    console.log(`[SUBSCRICOES] ✅ Estado atualizado: ${estadoAnterior} → ${novoEstado}`);
    console.log(`[SUBSCRICOES] - Motivo: ${dados.motivo}`);
    
    return {
      success: true,
      data: {
        subscricao,
        estadoAnterior,
        estadoNovo: novoEstado,
      },
    };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao atualizar estado:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Registrar renovação (pagamento recebido)
 */
export async function registrarRenovacao(
  empresaId: string,
  dados: {
    valorPago: number;
    metodoPagamento: string;
    movimentoFinanceiroId?: string;
    observacoes?: string;
    snapshotPlano?: Record<string, unknown>;
    planoId?: PlanoId;
    mesesPagos?: number;  // Quantos meses foram pagos (padrão: 1)
  }
): Promise<{ success: boolean; error?: string }> {
  try {
    console.log(`[SUBSCRICOES] 💰 Registrando renovação - Empresa: ${empresaId}, Valor: ${dados.valorPago}`);
    
    const subscricao = await obterSubscricao(empresaId);
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    
    const agora = new Date();
    const planoAnterior = subscricao.planoId;
    const plano = await obterPlanoConfiguradoPorId(dados.planoId || subscricao.planoId);
    const politica = await obterPoliticaSegura();
    const mesesPagos = dados.mesesPagos || plano?.cicloMeses || subscricao.cicloMeses || 1;
    const dataVencimentoAnterior = subscricao.dataProximaRenovacao;
    const vencimentoAtual = new Date(dataVencimentoAnterior);
    // Só estende a partir da data de vencimento actual quando a subscrição
    // estava mesmo ACTIVE (pagamento antecipado, dentro do ciclo em curso).
    // Se estava SUSPENDED/GRACE_PERIOD/PENDING_PAYMENT, dataProximaRenovacao
    // pode já ter sido empurrada para a frente por uma mudança de plano feita
    // sem pagamento (mudarPlano recalcula-a a partir de "agora" sempre que o
    // ciclo muda) - usar essa data como base somaria o novo ciclo a um valor
    // já adiantado "de borla". Neste caso a base é sempre "agora".
    const baseRenovacao =
      subscricao.estado === "ACTIVE" &&
      !Number.isNaN(vencimentoAtual.getTime()) &&
      vencimentoAtual > agora
        ? vencimentoAtual
        : agora;
    
    // Calcular próxima renovação (soma meses pagos * 30 dias)
    const proximaRenovacao = new Date(
      calcularProximaRenovacao(baseRenovacao, mesesPagos, plano?.id || subscricao.planoId, politica),
    );
    
    // Adicionar renovação ao histórico
    const renovacao: Renovacao = {
      data: agora.toISOString(),
      valorPago: dados.valorPago,
      metodoPagamento: dados.metodoPagamento,
      proximaRenovacao: proximaRenovacao.toISOString(),
      dataVencimentoAnterior,
      periodoInicio: baseRenovacao.toISOString(),
      periodoFim: proximaRenovacao.toISOString(),
      movimentoFinanceiroId: dados.movimentoFinanceiroId,
      snapshotPlano: dados.snapshotPlano,
      observacoes: dados.observacoes || `Pagamento de ${mesesPagos} ${mesesPagos === 1 ? 'mês' : 'meses'}`,
    };
    
    subscricao.historicoRenovacoes.push(renovacao);
    
    // Se estava suspensa ou pendente, reativar
    if (subscricao.estado !== "ACTIVE") {
      subscricao.historicoMudancas.push({
        data: agora.toISOString(),
        estadoAnterior: subscricao.estado,
        estadoNovo: "ACTIVE",
        motivo: `Pagamento recebido - ${dados.valorPago} MZN`,
        automatico: false,
      });
      
      subscricao.estado = "ACTIVE";
    }
    
    if (plano && plano.id !== planoAnterior) {
      subscricao.historicoMudancas.push({
        data: agora.toISOString(),
        estadoAnterior: subscricao.estado,
        estadoNovo: subscricao.estado,
        motivo: `Plano alterado no pagamento de renovacao - de ${planoAnterior} para ${plano.id}`,
        automatico: false,
      });
    }

    if (plano) {
      subscricao.planoId = plano.id;
      subscricao.valorMensalAtual = plano.avencaTotal;
      subscricao.valorRecorrenteAtual = plano.avencaTotal;
      subscricao.taxaLicencaUnica = plano.taxaInscricaoTotal;
    }

    subscricao.cicloMeses = mesesPagos;
    subscricao.valorRecorrenteAtual = subscricao.valorRecorrenteAtual || subscricao.valorMensalAtual;
    subscricao.dataProximaRenovacao = proximaRenovacao.toISOString();
    subscricao.dataUltimaAtualizacao = agora.toISOString();
    
    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);
    
    console.log(`[SUBSCRICOES] ✅ Renovação registrada`);
    console.log(`[SUBSCRICOES] - Valor pago: ${dados.valorPago} MZN`);
    console.log(`[SUBSCRICOES] - Meses pagos: ${mesesPagos}`);
    console.log(`[SUBSCRICOES] - Próxima renovação: ${proximaRenovacao.toISOString().split('T')[0]}`);
    console.log(`[SUBSCRICOES] - Estado: ${subscricao.estado}`);
    
    return { success: true };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao registrar renovação:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Mudar plano da subscrição
 */
export async function mudarPlano(
  empresaId: string,
  novoPlanoId: PlanoId,
  dados: {
    motivo: string;
    usuarioId?: string;
  }
): Promise<{ success: boolean; error?: string }> {
  try {
    console.log(`[SUBSCRICOES] 🔄 Mudando plano - Empresa: ${empresaId}, Novo plano: ${novoPlanoId}`);
    
    const subscricao = await obterSubscricao(empresaId);
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    
    const planoNovo = await obterPlanoConfiguradoPorId(novoPlanoId);
    if (!planoNovo) {
      return { success: false, error: `Plano '${novoPlanoId}' não encontrado` };
    }
    
    const planoAnterior = subscricao.planoId;
    const cicloAnterior = subscricao.cicloMeses || 1;
    const cicloNovo = planoNovo.cicloMeses || 1;
    const mudouCiclo = cicloNovo !== cicloAnterior;

    // Adicionar mudança de plano ao histórico
    subscricao.historicoMudancas.push({
      data: new Date().toISOString(),
      estadoAnterior: subscricao.estado,
      estadoNovo: subscricao.estado, // Estado não muda, só o plano
      motivo: mudouCiclo
        ? `${dados.motivo} - Plano alterado de ${planoAnterior} para ${novoPlanoId} (ciclo ${cicloAnterior}→${cicloNovo} meses; data de renovação recalculada). Esta ação não regista pagamento — use "Registar Pagamento" quando houver cobrança associada.`
        : `${dados.motivo} - Plano alterado de ${planoAnterior} para ${novoPlanoId}`,
      automatico: false,
      usuarioId: dados.usuarioId,
    });

    subscricao.planoId = novoPlanoId;
    subscricao.valorMensalAtual = planoNovo.avencaTotal;
    subscricao.cicloMeses = cicloNovo;
    subscricao.valorRecorrenteAtual = planoNovo.avencaTotal;
    subscricao.taxaLicencaUnica = planoNovo.taxaInscricaoTotal;
    subscricao.dataUltimaAtualizacao = new Date().toISOString();

    // Quando o ciclo (mensal/anual/etc.) muda, a data de renovação herdada do
    // ciclo anterior deixa de fazer sentido (ex: um cliente mudado de mensal
    // para anual ficaria com uma renovação anual a vencer em poucos dias,
    // gerando um aviso falso). Recalcula-se a partir de agora, com o novo
    // ciclo. Esta função não regista pagamento nem movimento financeiro —
    // isso é feito por registrarRenovacao (via /pagar-avenca ou
    // /subscricao/mpesa-renovar), que deve ser usada quando a mudança de
    // plano corresponde a uma cobrança real.
    if (mudouCiclo) {
      const politica = await obterPoliticaSegura();
      subscricao.dataProximaRenovacao = calcularProximaRenovacao(
        new Date(),
        cicloNovo,
        novoPlanoId,
        politica,
      );
    }

    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);

    console.log(`[SUBSCRICOES] ✅ Plano alterado: ${planoAnterior} → ${novoPlanoId}`);
    console.log(`[SUBSCRICOES] - Novo valor mensal: ${planoNovo.avencaTotal} MZN`);
    if (mudouCiclo) {
      console.log(`[SUBSCRICOES] - Ciclo alterado (${cicloAnterior}→${cicloNovo} meses); próxima renovação recalculada: ${subscricao.dataProximaRenovacao}`);
    }

    return { success: true };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao mudar plano:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Agenda uma mudança de plano para entrar em vigor só no início do próximo
 * ciclo (fim do ciclo actual, já pago) — ao contrário de mudarPlano(), que
 * troca o plano de imediato. O pagamento antecipado em si (o movimento
 * financeiro) é responsabilidade de quem chama esta função (ver rota
 * /empresas/:id/agendar-mudanca-plano em admin-router.tsx) — para evitar um
 * import circular com pagamentos.tsx (que já importa obterSubscricao daqui),
 * esta função só grava a referência do movimento já criado, tal como
 * registrarRenovacao() já faz com `movimentoFinanceiroId`.
 */
export async function agendarMudancaPlano(
  empresaId: string,
  novoPlanoId: PlanoId,
  dados: {
    movimentoFinanceiroId?: string;
    motivo?: string;
    usuarioId?: string;
  }
): Promise<{ success: boolean; error?: string; data?: { dataEfetivacao: string; planoNome: string } }> {
  try {
    const subscricao = await obterSubscricao(empresaId);
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }

    const planoNovo = await obterPlanoConfiguradoPorId(novoPlanoId);
    if (!planoNovo) {
      return { success: false, error: `Plano '${novoPlanoId}' não encontrado` };
    }

    if (novoPlanoId === subscricao.planoId) {
      return { success: false, error: "A empresa já está neste plano" };
    }

    const agora = new Date();
    const vencimentoActual = new Date(subscricao.dataProximaRenovacao);
    const emCicloActivo =
      subscricao.estado === "ACTIVE" &&
      !Number.isNaN(vencimentoActual.getTime()) &&
      vencimentoActual > agora;

    if (!emCicloActivo) {
      return {
        success: false,
        error:
          "Não há um ciclo actual em curso para agendar a mudança — use 'Registar Pagamento' para aplicar o novo plano de imediato.",
      };
    }

    const dataEfetivacao = subscricao.dataProximaRenovacao;

    subscricao.planoAgendadoId = novoPlanoId;
    subscricao.dataEfetivacaoAgendada = dataEfetivacao;
    subscricao.pagamentoAgendadoMovimentoId = dados.movimentoFinanceiroId;
    subscricao.historicoMudancas.push({
      data: agora.toISOString(),
      estadoAnterior: subscricao.estado,
      estadoNovo: subscricao.estado,
      motivo:
        dados.motivo ||
        `Mudança de plano agendada e paga antecipadamente: de ${subscricao.planoId} para ${novoPlanoId}, efectiva em ${dataEfetivacao.split("T")[0]}`,
      automatico: false,
      usuarioId: dados.usuarioId,
    });
    subscricao.dataUltimaAtualizacao = agora.toISOString();

    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);

    console.log(
      `[SUBSCRICOES] 📅 Mudança de plano agendada - Empresa: ${empresaId}, ${subscricao.planoId} → ${novoPlanoId}, efectiva em ${dataEfetivacao}`,
    );

    return { success: true, data: { dataEfetivacao, planoNome: planoNovo.nome } };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao agendar mudança de plano:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Cancela uma mudança de plano agendada (o pagamento já feito não é
 * automaticamente estornado — fica só um registo no histórico a assinalar
 * que precisa de revisão manual).
 */
export async function cancelarMudancaPlanoAgendada(
  empresaId: string,
  motivo: string,
): Promise<{ success: boolean; error?: string }> {
  try {
    const subscricao = await obterSubscricao(empresaId);
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    if (!subscricao.planoAgendadoId) {
      return { success: false, error: "Não há nenhuma mudança de plano agendada para cancelar" };
    }

    const agora = new Date();
    subscricao.historicoMudancas.push({
      data: agora.toISOString(),
      estadoAnterior: subscricao.estado,
      estadoNovo: subscricao.estado,
      motivo: `Mudança de plano agendada para ${subscricao.planoAgendadoId} foi cancelada — ${motivo}. ${
        subscricao.pagamentoAgendadoMovimentoId
          ? `Pagamento antecipado (movimento ${subscricao.pagamentoAgendadoMovimentoId}) precisa de revisão manual na conta corrente.`
          : ""
      }`,
      automatico: false,
    });

    subscricao.planoAgendadoId = undefined;
    subscricao.dataEfetivacaoAgendada = undefined;
    subscricao.pagamentoAgendadoMovimentoId = undefined;
    subscricao.dataUltimaAtualizacao = agora.toISOString();

    await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, subscricao);

    return { success: true };
  } catch (error: any) {
    return { success: false, error: error.message };
  }
}

/**
 * Suspender subscrição (usado pelo processo de renovação)
 */
export async function suspenderSubscricao(
  empresaId: string,
  motivo: string
): Promise<{ success: boolean; error?: string }> {
  return await atualizarEstadoSubscricao(empresaId, "SUSPENDED", {
    motivo,
    automatico: true,
  });
}

/**
 * Cancelar subscrição (ação manual do cliente)
 */
export async function cancelarSubscricao(
  empresaId: string,
  dados: {
    motivo: string;
    usuarioId?: string;
  }
): Promise<{ success: boolean; error?: string }> {
  return await atualizarEstadoSubscricao(empresaId, "CANCELED", {
    motivo: dados.motivo,
    automatico: false,
    usuarioId: dados.usuarioId,
  });
}

// ========== FUNÇÕES DE VALIDAÇÃO ==========

/**
 * Validar acesso a módulo (FUNÇÃO CENTRAL DE VALIDAÇÃO)
 */
export async function validarAcessoModulo(
  empresaId: string,
  moduloId: string
): Promise<{ permitido: boolean; motivo?: string; subscricao?: Subscricao }> {
  try {
    const politica = await obterPoliticaSegura();
    // CAMADA 1: Verificar se subscrição existe
    const subscricao = await obterSubscricao(empresaId);
    
    if (!subscricao) {
      return { 
        permitido: false, 
        motivo: "Empresa não possui subscrição ativa" 
      };
    }
    
    // CAMADA 2: Verificar estado da subscrição
    if (subscricao.estado === "SUSPENDED" && politica.alertasBloqueioAtivos !== false) {
      return { 
        permitido: false, 
        motivo: "Subscrição suspensa por falta de pagamento. Regularize para restaurar o acesso.",
        subscricao 
      };
    }
    
    if (subscricao.estado === "CANCELED") {
      return { 
        permitido: false, 
        motivo: "Subscrição cancelada. Contrate um novo plano para acessar os módulos.",
        subscricao 
      };
    }
    
    // CAMADA 3: Verificar vencimento e grace period
    if (subscricao.estado === "GRACE_PERIOD" && politica.alertasBloqueioAtivos !== false) {
      const dataRenovacao = new Date(subscricao.dataProximaRenovacao);
      const hoje = new Date();
      const horasAtraso = Math.floor(
        (hoje.getTime() - dataRenovacao.getTime()) / (1000 * 60 * 60)
      );
      const gracePeriodHoras = obterGracePeriodHoras(subscricao, politica);
      
      if (horasAtraso > gracePeriodHoras) {
        // Grace period excedido - deveria estar suspenso
        // (Processo automático deveria ter feito isso)
        await suspenderSubscricao(empresaId, `Grace period de ${gracePeriodHoras} horas excedido`);
        
        return { 
          permitido: false, 
          motivo: `Período de tolerância excedido (${horasAtraso} horas de atraso). Subscrição suspensa.`,
          subscricao 
        };
      }
      
      // Dentro do grace period - permitir com aviso
      return { 
        permitido: true, 
        motivo: `⚠️ Acesso permitido. Pagamento em atraso há ${horasAtraso} horas. Regularize em breve.`,
        subscricao 
      };
    }
    
    // CAMADA 4: Verificar se módulo está incluído no plano
    const plano = await obterPlanoConfiguradoPorId(subscricao.planoId);
    
    if (!plano) {
      return { 
        permitido: false, 
        motivo: `Plano '${subscricao.planoId}' não encontrado no sistema`,
        subscricao 
      };
    }
    
    if (!plano.modulos.includes(moduloId as any)) {
      return { 
        permitido: false, 
        motivo: `Módulo '${moduloId}' não está incluído no seu plano atual (${plano.nome}). Faça upgrade para acessar.`,
        subscricao 
      };
    }
    
    // ✅ TODAS AS VALIDAÇÕES PASSARAM
    return { 
      permitido: true,
      subscricao 
    };
    
  } catch (error: any) {
    console.error(`[SUBSCRICOES] Erro ao validar acesso:`, error);
    return { 
      permitido: false, 
      motivo: `Erro ao validar acesso: ${error.message}` 
    };
  }
}

/**
 * Obter status da subscrição (resumo para interface)
 */
export async function obterStatusSubscricao(empresaId: string): Promise<{
  success: boolean;
  data?: {
    subscricao: Subscricao;
    planoNome: string;
    modulosAtivos: string[];
    diasParaVencimento: number;
    minutosParaVencimento: number;
    notificacoesMinutos?: number[];
    notificacoesDias?: number[];
    modoTesteMinutos?: boolean;
    alertasBloqueioAtivos?: boolean;
    gracePeriodHoras?: number;
    snoozeMinutos?: number;
    pollingTesteSegundos?: number;
    pollingNormalMinutos?: number;
    statusPagamento: "em-dia" | "pendente" | "atrasado" | "suspenso";
  };
  error?: string;
}> {
  try {
    const subscricao = await obterSubscricao(empresaId);
    
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    
    const plano = await obterPlanoConfiguradoPorId(subscricao.planoId);
    
    if (!plano) {
      return { success: false, error: "Plano não encontrado" };
    }
    
    // Calcular dias para vencimento
    const dataRenovacao = new Date(subscricao.dataProximaRenovacao);
    const hoje = new Date();
    const diasParaVencimento = Math.floor(
      (dataRenovacao.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24)
    );
    const minutosParaVencimento = calcularMinutosParaVencimento(dataRenovacao, hoje);
    const politica = await obterPoliticaSegura();
    
    // Determinar status de pagamento
    let statusPagamento: "em-dia" | "pendente" | "atrasado" | "suspenso";
    
    if (subscricao.estado === "SUSPENDED") {
      statusPagamento = "suspenso";
    } else if (subscricao.estado === "GRACE_PERIOD") {
      statusPagamento = "atrasado";
    } else if (subscricao.estado === "PENDING_PAYMENT") {
      statusPagamento = "pendente";
    } else {
      statusPagamento = "em-dia";
    }
    
    return {
      success: true,
      data: {
        subscricao,
        planoNome: plano.nome,
        modulosAtivos: plano.modulos,
        diasParaVencimento,
        minutosParaVencimento,
        notificacoesMinutos: politica.alertasBloqueioAtivos !== false && politica.modoTesteMensal && subscricao.planoId === "mensal"
          ? politica.avisoMinutosTeste
          : undefined,
        notificacoesDias: politica.alertasBloqueioAtivos !== false ? politica.avisoDias : [],
        modoTesteMinutos: politica.alertasBloqueioAtivos !== false && politica.modoTesteMensal && subscricao.planoId === "mensal",
        alertasBloqueioAtivos: politica.alertasBloqueioAtivos !== false,
        gracePeriodHoras: obterGracePeriodHoras(subscricao, politica),
        snoozeMinutos: politica.snoozeMinutos,
        pollingTesteSegundos: politica.pollingTesteSegundos,
        pollingNormalMinutos: politica.pollingNormalMinutos,
        statusPagamento,
      }
    };
  } catch (error: any) {
    return { success: false, error: error.message };
  }
}

// ========== FUNÇÕES DE MIGRAÇO ==========

/**
 * Migrar dados de empresa existente para subscrição
 * (usado para empresas que já têm plano mas não têm subscrição)
 */
export async function migrarEmpresaParaSubscricao(
  empresaId: string,
  empresaData: {
    plano: string;
    valorAvenca: number;
    paymentStatus: string;
    proximoPagamento?: string;
  }
): Promise<{ success: boolean; data?: Subscricao; error?: string }> {
  try {
    console.log(`[SUBSCRICOES] 🔄 Migrando empresa ${empresaId} para subscrição`);
    
    // Verificar se já existe subscrição
    const existente = await obterSubscricao(empresaId);
    if (existente) {
      console.log(`[SUBSCRICOES] ⚠️ Empresa já possui subscrição, pulando migração`);
      return { success: true, data: existente };
    }
    
    // Mapear nome do plano para ID
    let planoId: PlanoId = "mensal"; // Padrão
    
    const planosCompatibilidade = await obterPlanosCompatibilidadeConfigurados();
    const planoEncontrado = planosCompatibilidade.find(p =>
      p.nome.toLowerCase() === empresaData.plano.toLowerCase()
    );
    
    if (planoEncontrado) {
      planoId = planoEncontrado.id;
    } else {
      console.warn(`[SUBSCRICOES] ⚠️ Plano '${empresaData.plano}' não encontrado, usando 'mensal' como padrão`);
    }
    
    // Determinar estado baseado no paymentStatus
    let estado: EstadoSubscricao = "ACTIVE";
    
    if (empresaData.paymentStatus === "atrasado") {
      estado = "GRACE_PERIOD";
    } else if (empresaData.paymentStatus === "pendente") {
      estado = "PENDING_PAYMENT";
    } else if (empresaData.paymentStatus === "suspenso") {
      estado = "SUSPENDED";
    }
    
    // Criar subscrição
    const resultado = await criarSubscricao(empresaId, planoId, {
      dataInicio: new Date().toISOString(), // Data de migração
      licencaPaga: true,
    });
    
    if (!resultado.success || !resultado.data) {
      return resultado;
    }
    
    if (empresaData.valorAvenca && empresaData.valorAvenca > 0) {
      resultado.data.valorMensalAtual = empresaData.valorAvenca;
      resultado.data.valorRecorrenteAtual = empresaData.valorAvenca;
      await kv.set(`${SUBSCRICAO_PREFIX}${empresaId}`, resultado.data);
    }

    // Atualizar estado se necessário
    if (estado !== "ACTIVE") {
      await atualizarEstadoSubscricao(empresaId, estado, {
        motivo: `Migração de dados - Status original: ${empresaData.paymentStatus}`,
        automatico: true,
      });
    }
    
    console.log(`[SUBSCRICOES] ✅ Migração concluída`);
    console.log(`[SUBSCRICOES] - Plano: ${planoId}`);
    console.log(`[SUBSCRICOES] - Estado: ${estado}`);
    
    return { success: true, data: resultado.data };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro na migração:`, error);
    return { success: false, error: error.message };
  }
}

// ========== FUNÇÕES DE SINCRONIZAÇÃO (FASE 4) ==========

/**
 * Sincronizar módulos com a subscrição (FONTE ÚNICA DE VERDADE)
 * 
 * Esta função garante que os módulos ativos correspondem exatamente
 * aos módulos incluídos no plano da subscrição.
 * 
 * IMPORTANTE: Esta é a ÚNICA forma de ativar/desativar módulos após Fase 4.
 */
export async function sincronizarModulosComSubscricao(
  empresaId: string
): Promise<{ success: boolean; error?: string; modulosAtualizados?: string[] }> {
  try {
    console.log(`[SUBSCRICOES] 🔄 Sincronizando módulos para empresa ${empresaId}`);
    
    // Obter subscrição (fonte de verdade)
    const subscricao = await obterSubscricao(empresaId);
    
    if (!subscricao) {
      return { success: false, error: "Subscrição não encontrada" };
    }
    
    // Buscar plano
    const plano = await obterPlanoConfiguradoPorId(subscricao.planoId);
    
    if (!plano) {
      return { success: false, error: `Plano '${subscricao.planoId}' não encontrado` };
    }
    
    // Módulos que DEVEM estar ativos (definidos pelo plano)
    const modulosDoPlano = plano.modulos;
    
    console.log(`[SUBSCRICOES] 📋 Módulos do plano ${plano.nome}:`, modulosDoPlano);
    
    // Importar módulo de módulos (necessário para atualizar)
    const modulos = await import("./modulos.tsx");
    
    // Buscar módulos atuais da empresa
    const modulosAtuais = await modulos.obterModulosEmpresa(empresaId);
    
    if (!modulosAtuais || modulosAtuais.length === 0) {
      // Se não existe configuração, aplicar plano
      console.log(`[SUBSCRICOES] 📝 Aplicando plano pela primeira vez`);
      
      const resultado = await modulos.aplicarPlano(empresaId, subscricao.planoId);
      
      if (!resultado.success) {
        return { success: false, error: resultado.error };
      }
      
      console.log(`[SUBSCRICOES] ✅ Plano aplicado com ${modulosDoPlano.length} módulos`);
      return { success: true, modulosAtualizados: modulosDoPlano as string[] };
    }
    
    // Sincronizar: garantir que apenas módulos do plano estão ativos
    const modulosAtualizados: string[] = [];
    
    // Lista de todos os módulos do sistema
    const TODOS_MODULOS = modulos.MODULOS_SISTEMA.map(m => m.id);
    
    // Criar array de módulos sincronizados
    const modulosSincronizados: any[] = [];
    
    for (const moduloSistema of modulos.MODULOS_SISTEMA) {
      const moduloId = moduloSistema.id;
      const deveEstarAtivo = modulosDoPlano.includes(moduloId);
      const moduloAtual = modulosAtuais.find(m => m.moduloId === moduloId);
      const estaAtivo = moduloAtual?.ativo || false;
      
      // Se estado está incorreto, registrar mudança
      if (deveEstarAtivo !== estaAtivo) {
        console.log(`[SUBSCRICOES] 🔧 Ajustando módulo '${moduloId}': ${estaAtivo} → ${deveEstarAtivo}`);
        modulosAtualizados.push(moduloId);
      }
      
      // Se módulo deve estar ativo, adicionar/atualizar
      if (deveEstarAtivo) {
        modulosSincronizados.push({
          moduloId,
          ativo: true,
          taxaInscricao: 0,
          avenca: 0,
          dataAtivacao: moduloAtual?.dataAtivacao || new Date().toISOString(),
        });
      }
    }
    
    // Salvar módulos sincronizados
    if (modulosAtualizados.length > 0 || modulosSincronizados.length !== modulosAtuais.filter(m => m.ativo).length) {
      await modulos.configurarModulosEmpresa(empresaId, modulosSincronizados);
      
      console.log(`[SUBSCRICOES] ✅ Sincronização concluída`);
      console.log(`[SUBSCRICOES] - Módulos ativos: ${modulosSincronizados.length}`);
      if (modulosAtualizados.length > 0) {
        console.log(`[SUBSCRICOES] - Módulos ajustados:`, modulosAtualizados);
      }
    } else {
      console.log(`[SUBSCRICOES] ✅ Módulos já estão sincronizados`);
    }
    
    return { success: true, modulosAtualizados };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro ao sincronizar módulos:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Sincronizar módulos de todas as empresas com subscrições
 * (Processo batch para garantir consistência)
 */
export async function sincronizarTodasAsEmpresas(): Promise<{
  success: boolean;
  data?: {
    total: number;
    sincronizadas: number;
    erros: number;
    detalhes: any[];
  };
  error?: string;
}> {
  try {
    console.log(`[SUBSCRICOES] 🔄 Iniciando sincronização em batch de todas as empresas`);
    
    const todasSubscricoes = await listarTodasSubscricoes();
    
    const resultados = {
      total: todasSubscricoes.length,
      sincronizadas: 0,
      erros: 0,
      detalhes: [] as any[],
    };
    
    for (const subscricao of todasSubscricoes) {
      const resultado = await sincronizarModulosComSubscricao(subscricao.empresaId);
      
      if (resultado.success) {
        resultados.sincronizadas++;
        resultados.detalhes.push({
          empresaId: subscricao.empresaId,
          status: "sincronizada",
          modulosAtualizados: resultado.modulosAtualizados || [],
        });
      } else {
        resultados.erros++;
        resultados.detalhes.push({
          empresaId: subscricao.empresaId,
          status: "erro",
          erro: resultado.error,
        });
      }
    }
    
    console.log(`[SUBSCRICOES] ===== RESULTADO DA SINCRONIZAÇÃO BATCH =====`);
    console.log(`[SUBSCRICOES] Total: ${resultados.total}`);
    console.log(`[SUBSCRICOES] Sincronizadas: ${resultados.sincronizadas}`);
    console.log(`[SUBSCRICOES] Erros: ${resultados.erros}`);
    
    return { success: true, data: resultados };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] ❌ Erro na sincronização batch:`, error);
    return { success: false, error: error.message };
  }
}

// ========== FUNÇÕES DE RENOVAÇÃO AUTOMÁTICA (FASE 5) ==========

/**
 * Processar renovações de todas as subscrições
 * 
 * Esta função deve ser executada DIARIAMENTE para:
 * 1. Verificar subscrições vencidas
 * 2. Transicionar estados automaticamente
 * 3. Suspender subscrições que excederam grace period
 * 
 * IMPORTANTE: Executar via CRON job ou manualmente
 */
export async function processarRenovacoes(): Promise<{
  success: boolean;
  data?: {
    total: number;
    emDia: number;
    pendentes: number;
    gracePeriod: number;
    suspensas: number;
    canceladas: number;
    acoes: {
      paraGracePeriod: number;
      paraSuspensas: number;
    };
    detalhes: any[];
  };
  error?: string;
}> {
  try {
    console.log(`[RENOVACAO] ===== PROCESSANDO RENOVAÇÕES =====`);
    console.log(`[RENOVACAO] Data/Hora: ${new Date().toISOString()}`);
    
    const todasSubscricoes = await listarTodasSubscricoes();
    const politica = await obterPoliticaSegura();
    const hoje = new Date();
    
    const resultados = {
      total: todasSubscricoes.length,
      emDia: 0,
      pendentes: 0,
      gracePeriod: 0,
      suspensas: 0,
      canceladas: 0,
      acoes: {
        paraGracePeriod: 0,
        paraSuspensas: 0,
      },
      detalhes: [] as any[],
    };
    
    for (const subscricao of todasSubscricoes) {
      try {
        const dataRenovacao = new Date(subscricao.dataProximaRenovacao);
        const msAteVencimento = dataRenovacao.getTime() - hoje.getTime();
        const diasAteVencimento = Math.floor(msAteVencimento / (1000 * 60 * 60 * 24));
        
        let acao: string | null = null;
        let novoEstado: EstadoSubscricao | null = null;

        // REGRA 0: Há uma mudança de plano agendada (já paga antecipadamente)
        // e o ciclo actual já terminou — aplicar o novo plano agora, em vez
        // de tratar isto como um vencimento normal (o que a empurraria para
        // PENDING_PAYMENT indevidamente, já que isto já está pago).
        if (
          subscricao.planoAgendadoId &&
          subscricao.dataEfetivacaoAgendada &&
          new Date(subscricao.dataEfetivacaoAgendada).getTime() <= hoje.getTime()
        ) {
          const planoAgendado = await obterPlanoConfiguradoPorId(subscricao.planoAgendadoId);
          if (planoAgendado) {
            const planoAnterior = subscricao.planoId;
            const cicloNovo = planoAgendado.cicloMeses || 1;
            const novaProximaRenovacao = calcularProximaRenovacao(
              new Date(subscricao.dataEfetivacaoAgendada),
              cicloNovo,
              planoAgendado.id,
              politica,
            );

            subscricao.historicoMudancas.push({
              data: hoje.toISOString(),
              estadoAnterior: subscricao.estado,
              estadoNovo: "ACTIVE",
              motivo: `Mudança de plano agendada aplicada automaticamente: ${planoAnterior} → ${planoAgendado.id} (já paga antecipadamente)`,
              automatico: true,
            });

            subscricao.planoId = planoAgendado.id;
            subscricao.valorMensalAtual = planoAgendado.avencaTotal;
            subscricao.valorRecorrenteAtual = planoAgendado.avencaTotal;
            subscricao.taxaLicencaUnica = planoAgendado.taxaInscricaoTotal;
            subscricao.cicloMeses = cicloNovo;
            subscricao.dataProximaRenovacao = novaProximaRenovacao;
            subscricao.estado = "ACTIVE";
            subscricao.planoAgendadoId = undefined;
            subscricao.dataEfetivacaoAgendada = undefined;
            subscricao.pagamentoAgendadoMovimentoId = undefined;
            subscricao.dataUltimaAtualizacao = hoje.toISOString();

            await kv.set(`${SUBSCRICAO_PREFIX}${subscricao.empresaId}`, subscricao);
            await sincronizarModulosComSubscricao(subscricao.empresaId);
            await empresasModule.atualizarEmpresaSemValidacao(subscricao.empresaId, {
              paymentStatus: "em-dia",
              plano: planoAgendado.nome,
              proximoPagamento: novaProximaRenovacao.split("T")[0],
            });

            resultados.emDia++;
            resultados.detalhes.push({
              empresaId: subscricao.empresaId,
              planoId: planoAgendado.id,
              estadoAnterior: "ACTIVE",
              estadoFinal: "ACTIVE",
              diasAteVencimento: null,
              acao: `Mudança de plano agendada aplicada: ${planoAnterior} → ${planoAgendado.id}`,
              dataProximaRenovacao: novaProximaRenovacao,
            });

            continue;
          }
        }

        // REGRA 1: Se está ACTIVE e venceu, mover para PENDING_PAYMENT
        if (subscricao.estado === "ACTIVE" && msAteVencimento <= 0) {
          novoEstado = "PENDING_PAYMENT";
          acao = "Vencimento detectado - Movendo para PENDING_PAYMENT";
        }
        
        // REGRA 2: Se está PENDING_PAYMENT e passou do vencimento, mover para GRACE_PERIOD
        if (subscricao.estado === "PENDING_PAYMENT" && msAteVencimento < 0) {
          novoEstado = "GRACE_PERIOD";
          acao = "Pagamento atrasado - Iniciando grace period";
          resultados.acoes.paraGracePeriod++;
        }
        
        // REGRA 3: Se está GRACE_PERIOD e excedeu os dias de tolerância, SUSPENDER
        if (subscricao.estado === "GRACE_PERIOD") {
          const horasAtraso = Math.floor(Math.abs(msAteVencimento) / (1000 * 60 * 60));
          const gracePeriodHoras = obterGracePeriodHoras(subscricao, politica);
          
          if (horasAtraso > gracePeriodHoras) {
            novoEstado = "SUSPENDED";
            acao = `Grace period de ${gracePeriodHoras} horas excedido (${horasAtraso} horas de atraso) - SUSPENDENDO`;
            resultados.acoes.paraSuspensas++;
          }
        }
        
        // Executar transição de estado se necessário
        if (novoEstado && novoEstado !== subscricao.estado) {
          console.log(`[RENOVACAO] 🔄 Empresa ${subscricao.empresaId}: ${subscricao.estado} → ${novoEstado}`);
          console.log(`[RENOVACAO] - Motivo: ${acao}`);
          
          await atualizarEstadoSubscricao(subscricao.empresaId, novoEstado, {
            motivo: acao,
            automatico: true,
          });
        }
        
        // Contar por estado (usar novo estado se houve transição)
        const estadoFinal = novoEstado || subscricao.estado;
        
        switch (estadoFinal) {
          case "ACTIVE":
            resultados.emDia++;
            break;
          case "PENDING_PAYMENT":
            resultados.pendentes++;
            break;
          case "GRACE_PERIOD":
            resultados.gracePeriod++;
            break;
          case "SUSPENDED":
            resultados.suspensas++;
            break;
          case "CANCELED":
            resultados.canceladas++;
            break;
        }
        
        // Adicionar ao relatório
        resultados.detalhes.push({
          empresaId: subscricao.empresaId,
          planoId: subscricao.planoId,
          estadoAnterior: subscricao.estado,
          estadoFinal: estadoFinal,
          diasAteVencimento,
          acao: acao || "Nenhuma ação necessária",
          dataProximaRenovacao: subscricao.dataProximaRenovacao,
        });
        
      } catch (erro: any) {
        console.error(`[RENOVACAO] ❌ Erro ao processar empresa ${subscricao.empresaId}:`, erro);
        resultados.detalhes.push({
          empresaId: subscricao.empresaId,
          erro: erro.message,
        });
      }
    }
    
    console.log(`[RENOVACAO] ===== RESULTADO DO PROCESSAMENTO =====`);
    console.log(`[RENOVACAO] Total de subscrições: ${resultados.total}`);
    console.log(`[RENOVACAO] Em dia: ${resultados.emDia}`);
    console.log(`[RENOVACAO] Pendentes: ${resultados.pendentes}`);
    console.log(`[RENOVACAO] Grace period: ${resultados.gracePeriod}`);
    console.log(`[RENOVACAO] Suspensas: ${resultados.suspensas}`);
    console.log(`[RENOVACAO] Canceladas: ${resultados.canceladas}`);
    console.log(`[RENOVACAO] ===== AÇÕES EXECUTADAS =====`);
    console.log(`[RENOVACAO] Movidas para Grace Period: ${resultados.acoes.paraGracePeriod}`);
    console.log(`[RENOVACAO] Suspensas: ${resultados.acoes.paraSuspensas}`);
    
    return { success: true, data: resultados };
  } catch (error: any) {
    console.error(`[RENOVACAO] ❌ Erro no processamento de renovações:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Listar subscrições por estado
 * Útil para relatórios e monitoramento
 */
export async function listarSubscricoesPorEstado(
  estado: EstadoSubscricao
): Promise<Subscricao[]> {
  try {
    const todas = await listarTodasSubscricoes();
    return todas.filter(s => s.estado === estado);
  } catch (error) {
    console.error(`[SUBSCRICOES] Erro ao listar por estado:`, error);
    return [];
  }
}

/**
 * Obter relatório de vencimentos próximos
 * Retorna subscrições que vencem nos próximos N dias
 */
export async function obterRelatorioVencimentos(
  diasProximos: number = 7
): Promise<{
  success: boolean;
  data?: {
    total: number;
    vencendoEm: {
      dias: number;
      subscricoes: Array<{
        empresaId: string;
        planoId: string;
        dataProximaRenovacao: string;
        diasRestantes: number;
        valorMensal: number;
      }>;
    }[];
  };
  error?: string;
}> {
  try {
    const todas = await listarTodasSubscricoes();
    const hoje = new Date();
    
    // Filtrar apenas subscrições ativas ou pendentes
    const subscricoesAtivas = todas.filter(
      s => s.estado === "ACTIVE" || s.estado === "PENDING_PAYMENT"
    );
    
    const vencimentos: any[] = [];
    
    for (const subscricao of subscricoesAtivas) {
      const dataRenovacao = new Date(subscricao.dataProximaRenovacao);
      const diasRestantes = Math.floor(
        (dataRenovacao.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24)
      );
      
      // Se vence nos próximos N dias
      if (diasRestantes >= 0 && diasRestantes <= diasProximos) {
        vencimentos.push({
          empresaId: subscricao.empresaId,
          planoId: subscricao.planoId,
          dataProximaRenovacao: subscricao.dataProximaRenovacao,
          diasRestantes,
          valorMensal: calcularValorMensalEquivalente(subscricao),
          valorRecorrente: subscricao.valorRecorrenteAtual || subscricao.valorMensalAtual,
          cicloMeses: subscricao.cicloMeses || 1,
        });
      }
    }
    
    // Agrupar por dias restantes
    const agrupado: any = {};
    
    for (let dia = 0; dia <= diasProximos; dia++) {
      agrupado[dia] = vencimentos.filter(v => v.diasRestantes === dia);
    }
    
    const vencendoEm = Object.entries(agrupado)
      .filter(([_, subs]: any) => subs.length > 0)
      .map(([dias, subscricoes]) => ({
        dias: parseInt(dias),
        subscricoes,
      }));
    
    console.log(`[SUBSCRICOES] Relatório de vencimentos - Próximos ${diasProximos} dias`);
    console.log(`[SUBSCRICOES] Total de vencimentos: ${vencimentos.length}`);
    
    return {
      success: true,
      data: {
        total: vencimentos.length,
        vencendoEm,
      },
    };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] Erro ao gerar relatório:`, error);
    return { success: false, error: error.message };
  }
}

/**
 * Obter estatísticas gerais de subscrições
 */
export async function obterEstatisticas(): Promise<{
  success: boolean;
  data?: {
    total: number;
    porEstado: {
      [key: string]: number;
    };
    porPlano: {
      [key: string]: number;
    };
    receitaMensalTotal: number;
    receitaMensalPorPlano: {
      [key: string]: number;
    };
  };
  error?: string;
}> {
  try {
    const todas = await listarTodasSubscricoes();
    
    const stats = {
      total: todas.length,
      porEstado: {} as any,
      porPlano: {} as any,
      receitaMensalTotal: 0,
      receitaMensalPorPlano: {} as any,
    };
    
    // Contar por estado
    for (const subscricao of todas) {
      // Estado
      if (!stats.porEstado[subscricao.estado]) {
        stats.porEstado[subscricao.estado] = 0;
      }
      stats.porEstado[subscricao.estado]++;
      
      // Plano
      if (!stats.porPlano[subscricao.planoId]) {
        stats.porPlano[subscricao.planoId] = 0;
      }
      stats.porPlano[subscricao.planoId]++;
      
      // Receita (apenas subscrições ativas)
      if (subscricao.estado === "ACTIVE" || subscricao.estado === "PENDING_PAYMENT") {
        const receitaMensalEquivalente = calcularValorMensalEquivalente(subscricao);
        stats.receitaMensalTotal += receitaMensalEquivalente;
        
        if (!stats.receitaMensalPorPlano[subscricao.planoId]) {
          stats.receitaMensalPorPlano[subscricao.planoId] = 0;
        }
        stats.receitaMensalPorPlano[subscricao.planoId] += receitaMensalEquivalente;
      }
    }
    
    return { success: true, data: stats };
  } catch (error: any) {
    console.error(`[SUBSCRICOES] Erro ao obter estatísticas:`, error);
    return { success: false, error: error.message };
  }
}
