import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { PrismaService } from '../../prisma/prisma.service';
import { WebhookService } from '../webhooks/webhook.service';
import { CarteraIaService } from './cartera-ia.service';

/**
 * Cron que ejecuta el resumen IA del día por cada empresa que tenga
 * activado `recomendaciones_auto_activas` y cuya hora configurada
 * (`recomendaciones_auto_hora`) coincida con la hora actual.
 *
 * Diseño:
 *  - Corre cada hora (a los 5 minutos para no clashear con otros crons).
 *  - Por cada empresa elegible:
 *      1. Llama a `CarteraIaService.resumenDia()` con forceRefresh=true
 *         (asegura cálculo fresco del día, no del cache de ayer).
 *      2. Por cada prioridad del resumen, emite webhook
 *         `recomendacion.alta_prioridad` (los endpoints suscritos en la
 *         empresa lo reciben).
 *      3. Marca `ultimo_recomendaciones_auto_at = NOW()` para evitar doble
 *         ejecución si el cron se reinicia dentro de la misma hora.
 *  - Errores por empresa no propagan: se loguean y el cron sigue con la
 *    próxima empresa.
 *
 * El usuario tiene control total:
 *  - Por defecto está OFF (opt-in).
 *  - Se activa desde la UI: Cartera Inteligente → Configuración operativa.
 *  - Cambiar la hora cambia el horario sin reinicio del servidor.
 */
@Injectable()
export class CarteraRecomendacionesCron {
  private readonly logger = new Logger(CarteraRecomendacionesCron.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly ia: CarteraIaService,
    private readonly webhooks: WebhookService,
  ) {}

  @Cron('5 * * * *') // todos los días, cada hora, al minuto 5
  async tickHorario(): Promise<void> {
    const ahora = new Date();
    const horaActual = ahora.getHours();

    const configs = await this.prisma.tenant_cartera_config.findMany({
      where: {
        recomendaciones_auto_activas: true,
        recomendaciones_auto_hora: horaActual,
      },
      select: {
        empresa_id: true,
        ultimo_recomendaciones_auto_at: true,
      },
    });

    if (configs.length === 0) return;

    this.logger.log(
      `Tick recomendaciones IA — hora=${horaActual}, empresas elegibles=${configs.length}`,
    );

    for (const c of configs) {
      // Anti doble-corrida en la misma hora si el cron se reinicia.
      if (this.yaCorrioHoy(c.ultimo_recomendaciones_auto_at, ahora)) {
        this.logger.debug(`Empresa ${c.empresa_id}: ya corrió hoy, skip`);
        continue;
      }

      try {
        await this.procesarEmpresa(c.empresa_id);
      } catch (err: any) {
        this.logger.error(
          `Empresa ${c.empresa_id} falló: ${err?.message ?? err}`,
        );
      }

      await this.prisma.tenant_cartera_config.update({
        where: { empresa_id: c.empresa_id },
        data: { ultimo_recomendaciones_auto_at: new Date() },
      });
    }
  }

  private async procesarEmpresa(empresa_id: string): Promise<void> {
    const resumen = await this.ia.resumenDia(empresa_id, { forceRefresh: true });

    if (resumen.prioridades_dia.length === 0) {
      this.logger.log(`Empresa ${empresa_id}: sin prioridades — no se emiten webhooks.`);
      return;
    }

    // Un webhook por prioridad — permite enrutado fino del lado cliente.
    for (let i = 0; i < resumen.prioridades_dia.length; i++) {
      const p = resumen.prioridades_dia[i];
      try {
        await this.webhooks.publicar(empresa_id, 'recomendacion.alta_prioridad', {
          rank: i + 1,
          cliente_id: p.cliente_id,
          cliente_nombre: p.cliente_nombre,
          cuenta_id: p.cuenta_id,
          razon: p.razon,
          accion_sugerida: p.accion_sugerida,
          salud_cartera: resumen.salud_cartera,
          generado_en: resumen.generado_en,
          origen: 'cartera-inteligente-cron',
        });
      } catch (err: any) {
        // WebhookService ya tiene catch interno pero por defensa adicional.
        this.logger.warn(
          `Webhook recomendacion.alta_prioridad falló para ${empresa_id}/${p.cliente_id}: ${err?.message ?? err}`,
        );
      }
    }

    this.logger.log(
      `Empresa ${empresa_id}: ${resumen.prioridades_dia.length} recomendaciones emitidas (salud=${resumen.salud_cartera})`,
    );
  }

  private yaCorrioHoy(ultimaEjecucion: Date | null, ahora: Date): boolean {
    if (!ultimaEjecucion) return false;
    return (
      ultimaEjecucion.getFullYear() === ahora.getFullYear() &&
      ultimaEjecucion.getMonth() === ahora.getMonth() &&
      ultimaEjecucion.getDate() === ahora.getDate() &&
      ultimaEjecucion.getHours() === ahora.getHours()
    );
  }
}
