import type { Pool } from 'pg';
import { prisma } from '../config/database.js';
import { emailService } from './email/email.service.js';
import { getTenantOwnerEmails, getUserEmailById } from '../utils/memberships.js';
import { env } from '../config/env.js';
import { getContribuyenteEmailPreferences } from './notification-preferences.service.js';
import type { DocumentoSubidoData } from './email/templates/documento-subido.js';

/**
 * Notifica a los destinatarios relevantes cuando se sube una declaración
 * o un documento extra. Destinatarios:
 *   - Owners activos del despacho (getTenantOwnerEmails)
 *   - Supervisor del contribuyente (entidades_gestionadas.supervisor_user_id),
 *     si existe y no coincide con un owner ya incluido
 *
 * El uploader mismo SE EXCLUYE (no tiene sentido notificarle su propia acción).
 *
 * Fire-and-forget: el caller hace `.catch()` y esta función no re-lanza.
 * Fail-soft: si SMTP no está configurado, los envíos se loguean a consola
 * vía el transport de @horux/core.
 */
export async function notifyDocumentoSubido(params: {
  pool: Pool;
  tenantId: string;
  contribuyenteId: string | null;
  subidoPor: string;
  kind: DocumentoSubidoData['kind'];
  declaracion?: DocumentoSubidoData['declaracion'];
  extra?: DocumentoSubidoData['extra'];
}): Promise<void> {
  const { pool, tenantId, contribuyenteId, subidoPor } = params;

  // 1. Datos del contribuyente (desde BD tenant). Sin contribuyenteId no hay
  // subject informativo ni supervisor — skip.
  if (!contribuyenteId) return;

  // Respeta preferencias de notificación del contribuyente. Si el user
  // desactivó `documento_subido` para este contribuyente, no enviar.
  const prefs = await getContribuyenteEmailPreferences(pool, contribuyenteId);
  if (!prefs.documento_subido) return;

  const { rows } = await pool.query<{
    rfc: string;
    nombre: string;
    supervisor_user_id: string | null;
  }>(
    `SELECT c.rfc, eg.nombre, eg.supervisor_user_id
     FROM contribuyentes c
     JOIN entidades_gestionadas eg ON eg.id = c.entidad_id
     WHERE c.entidad_id = $1`,
    [contribuyenteId.replace(/[^a-f0-9-]/gi, '')],
  );
  if (rows.length === 0) return;
  const contrib = rows[0];

  // 2. Recipients. Owners primero; luego supervisor si aplica.
  const owners = await getTenantOwnerEmails(tenantId);
  const recipients = new Set<string>(owners);

  if (contrib.supervisor_user_id) {
    const supervisorEmail = await getUserEmailById(contrib.supervisor_user_id);
    if (supervisorEmail) recipients.add(supervisorEmail);
  }

  // Excluir al uploader: no notificarle su propia acción.
  recipients.delete(subidoPor.toLowerCase());
  recipients.delete(subidoPor);

  if (recipients.size === 0) return;

  // 3. Datos del despacho (para mostrar en el body).
  const tenant = await prisma.tenant.findUnique({
    where: { id: tenantId },
    select: { nombre: true },
  });

  // 4. Link al sistema. Usa FRONTEND_URL del env.
  const link = `${env.FRONTEND_URL}/documentos`;

  await emailService.sendDocumentoSubido(Array.from(recipients), {
    kind: params.kind,
    subidoPor,
    contribuyenteRfc: contrib.rfc,
    contribuyenteNombre: contrib.nombre,
    despachoNombre: tenant?.nombre,
    declaracion: params.declaracion,
    extra: params.extra,
    link,
  });
}
