/**
 * Cron Lunes 8:00 AM (America/Mexico_City) que envía a cada owner activo de
 * cada tenant un correo "Actualización semanal" con KPIs del mes en curso +
 * alertas automáticas + breakdown mensual de discrepancias de régimen.
 *
 * Manejo de errores: por-tenant try/catch — si falla uno, los demás siguen.
 * Si SMTP no está configurado el email service logea a consola (dev), así
 * que el job es seguro de correr en cualquier ambiente.
 */
import cron from 'node-cron';
import { prisma } from '../config/database.js';
import { tenantDb } from '../config/database.js';
import { getKpis } from '../services/dashboard.service.js';
import { generarAlertasAutomaticas, getDiscrepanciasPorMes } from '../services/alertas-auto.service.js';
import { emailService } from '../services/email/email.service.js';

const SCHEDULE = '0 8 * * 1'; // Lunes 8:00 AM

let task: ReturnType<typeof cron.schedule> | null = null;

function currentMonthRange(now = new Date()): { fechaInicio: string; fechaFin: string; periodoLabel: string } {
  const año = now.getFullYear();
  const mes = now.getMonth();
  const inicio = new Date(año, mes, 1);
  const fin = new Date(año, mes + 1, 0);
  const NOMBRES = ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'];
  return {
    fechaInicio: inicio.toISOString().split('T')[0],
    fechaFin: fin.toISOString().split('T')[0],
    periodoLabel: `${NOMBRES[mes]} ${año}`,
  };
}

/**
 * Genera y envía el correo para UN tenant. Exportado para que pueda llamarse
 * manualmente desde un endpoint admin (p.ej. "Enviar reporte ahora").
 */
export async function sendWeeklyUpdateForTenant(tenantId: string): Promise<{ sent: number }> {
  const tenant = await prisma.tenant.findUnique({
    where: { id: tenantId },
    select: { id: true, nombre: true, rfc: true, active: true, databaseName: true },
  });
  if (!tenant || !tenant.active) {
    console.log(`[Weekly] Tenant ${tenantId} no encontrado o inactivo, skip`);
    return { sent: 0 };
  }

  // Recipientes: owners activos del tenant
  const owners = await prisma.tenantMembership.findMany({
    where: { tenantId, isOwner: true, active: true },
    include: { user: { select: { email: true, nombre: true, active: true } } },
  });
  const recipients = owners.filter(o => o.user.active);
  if (recipients.length === 0) {
    console.log(`[Weekly] Tenant ${tenant.rfc} sin owners activos, skip`);
    return { sent: 0 };
  }

  // Pool del tenant para queries de CFDI
  const pool = await tenantDb.getPool(tenantId, tenant.databaseName);

  const { fechaInicio, fechaFin, periodoLabel } = currentMonthRange();

  // Ejecuta los 3 colectores en paralelo
  const [kpis, alertas, discrepanciasPorMes] = await Promise.all([
    getKpis(pool, fechaInicio, fechaFin, tenant.id, false),
    generarAlertasAutomaticas(pool, tenant.id),
    getDiscrepanciasPorMes(pool, tenant.id, 6),
  ]);

  const fechaGeneracion = new Date().toLocaleString('es-MX', {
    dateStyle: 'long',
    timeStyle: 'short',
    timeZone: 'America/Mexico_City',
  });

  let sent = 0;
  for (const r of recipients) {
    try {
      await emailService.sendWeeklyUpdate(r.user.email, {
        nombre: r.user.nombre,
        empresa: tenant.nombre,
        periodoLabel,
        kpis: {
          ingresos: kpis.ingresos,
          egresos: kpis.egresos,
          utilidad: kpis.utilidad,
          margen: kpis.margen,
          ivaBalance: kpis.ivaBalance,
          ivaAFavorAcumulado: kpis.ivaAFavorAcumulado,
          cfdisEmitidos: kpis.cfdisEmitidos,
          cfdisRecibidos: kpis.cfdisRecibidos,
        },
        alertas: alertas.map(a => ({ titulo: a.titulo, mensaje: a.mensaje, prioridad: a.prioridad })),
        discrepanciasPorMes: discrepanciasPorMes.map(d => ({ label: d.label, count: d.count })),
        fechaGeneracion,
      });
      sent++;
    } catch (err: any) {
      console.error(`[Weekly] Error enviando a ${r.user.email} (tenant ${tenant.rfc}):`, err.message || err);
    }
  }

  console.log(`[Weekly] Tenant ${tenant.rfc}: ${sent}/${recipients.length} correos enviados`);
  return { sent };
}

/**
 * Itera todos los tenants activos y dispara `sendWeeklyUpdateForTenant`.
 * Por-tenant try/catch para que un fallo no bloquee al resto.
 */
export async function runWeeklyUpdate(): Promise<{ tenants: number; emails: number }> {
  const tenants = await prisma.tenant.findMany({
    where: { active: true },
    select: { id: true, rfc: true },
  });

  let totalEmails = 0;
  for (const t of tenants) {
    try {
      const { sent } = await sendWeeklyUpdateForTenant(t.id);
      totalEmails += sent;
    } catch (err: any) {
      console.error(`[Weekly] Tenant ${t.rfc} fallo completo:`, err.message || err);
    }
  }

  return { tenants: tenants.length, emails: totalEmails };
}

export function startWeeklyUpdateJob(): void {
  if (task) {
    console.warn('[Weekly Cron] Ya iniciado');
    return;
  }
  task = cron.schedule(SCHEDULE, async () => {
    try {
      const result = await runWeeklyUpdate();
      console.log(`[Weekly Cron] Reporte enviado: ${result.emails} correos a ${result.tenants} tenants`);
    } catch (err: any) {
      console.error('[Weekly Cron] Error general:', err.message || err);
    }
  }, {
    timezone: 'America/Mexico_City',
  });
  console.log(`[Weekly Cron] Programado: ${SCHEDULE} (Lunes 8:00 AM America/Mexico_City)`);
}

export function stopWeeklyUpdateJob(): void {
  if (task) {
    task.stop();
    task = null;
  }
}
