import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { PrismaService } from 'src/prisma/prisma.service';
import { RecalculoService } from './recalculo.service';

/**
 * Cron job que revisa la frecuencia configurada de cada empresa
 * y ejecuta el recálculo cuando corresponde.
 *
 * Corre cada hora — pero respeta el cron de cada empresa.
 * Esto permite frecuencias configurables sin múltiples cron jobs.
 */
@Injectable()
export class RecalculoCron {
  private readonly logger = new Logger(RecalculoCron.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly recalculo: RecalculoService,
  ) {}

  @Cron(CronExpression.EVERY_HOUR)
  async verificarYEjecutar(): Promise<void> {
    const ahora = new Date();

    const configs = await this.prisma.ai_empresa_config.findMany({
      // Doble gate: empresa con IA activa Y con recálculo automático habilitado.
      // Si el usuario desactiva el toggle, el cron deja de generar insights
      // automáticamente pero el módulo IA sigue disponible (chat, recomendaciones,
      // recálculo manual). Esto da control fino sobre el consumo de tokens.
      where: { activo: true, recalculo_automatico: true },
      select: {
        empresa_id: true,
        frecuencia_cron: true,
        ultimo_recalculo: true,
      },
    });

    for (const config of configs) {
      if (this.debeEjecutar(config.frecuencia_cron, config.ultimo_recalculo, ahora)) {
        this.logger.log(`Ejecutando recálculo programado empresa ${config.empresa_id}`);
        try {
          await this.recalculo.ejecutar(config.empresa_id);
        } catch (e) {
          this.logger.error(`Error en cron empresa ${config.empresa_id}`, e);
        }
      }
    }
  }

  /**
   * Determina si debe ejecutarse basado en el cron expression y el último recálculo.
   * Lógica simple: compara la hora actual con la hora definida en el cron.
   * Por ejemplo "0 2 * * *" = ejecutar a las 2:00 AM.
   */
  private debeEjecutar(cronExpr: string, ultimoRecalculo: Date | null, ahora: Date): boolean {
    try {
      const partes = cronExpr.trim().split(/\s+/);
      if (partes.length < 5) return false;

      const [minCron, horaCron] = partes;

      // Si es "*" en cualquiera de los dos primeros, ejecutar cada hora/minuto
      if (horaCron === '*') return true;

      const horaObjetivo = parseInt(horaCron, 10);
      const minObjetivo = minCron === '*' ? 0 : parseInt(minCron, 10);

      if (isNaN(horaObjetivo)) return false;

      const horaActual = ahora.getHours();
      const minActual = ahora.getMinutes();

      // Verificar si estamos en la hora objetivo (con margen de 1 hora)
      if (horaActual !== horaObjetivo) return false;
      if (Math.abs(minActual - minObjetivo) > 59) return false;

      // Verificar que no se ejecutó hoy ya
      if (ultimoRecalculo) {
        const mismodia =
          ultimoRecalculo.getFullYear() === ahora.getFullYear() &&
          ultimoRecalculo.getMonth() === ahora.getMonth() &&
          ultimoRecalculo.getDate() === ahora.getDate();
        if (mismodia) return false;
      }

      return true;
    } catch {
      return false;
    }
  }
}
