import type { Pool } from 'pg';

/**
 * Tipos de correos informativos cuyo envío puede desactivarse por
 * contribuyente. NO incluye correos transaccionales críticos
 * (welcome, password-reset, payment-*) — esos siempre se envían.
 *
 * Estado de implementación:
 * - documento_subido: ✅ implementado (notify-upload.service.ts)
 * - weekly_update:    ⏳ pendiente (job es tenant-wide hoy)
 * - subscription_expiring: ⏳ pendiente (no es per-contribuyente hoy)
 * - recordatorio_fiscal:   ⏳ placeholder para futuras alertas
 */
export const EMAIL_TYPES = [
  'documento_subido',
  'weekly_update',
  'subscription_expiring',
  'recordatorio_fiscal',
] as const;

export type EmailType = (typeof EMAIL_TYPES)[number];

export type EmailPreferences = Record<EmailType, boolean>;

/**
 * Default: todo activado. Si el JSONB en BD viene vacío o falta una
 * key, asumimos `true` para preservar el comportamiento previo.
 */
function applyDefaults(raw: Partial<Record<string, unknown>>): EmailPreferences {
  const out = {} as EmailPreferences;
  for (const t of EMAIL_TYPES) {
    out[t] = raw[t] === false ? false : true;
  }
  return out;
}

function sanitizeUuid(id: string): string {
  return id.replace(/[^a-f0-9-]/gi, '');
}

/**
 * Lee las preferencias de un contribuyente. Devuelve defaults (todo
 * activado) si no hay fila o la columna está vacía.
 */
export async function getContribuyenteEmailPreferences(
  pool: Pool,
  contribuyenteId: string,
): Promise<EmailPreferences> {
  const safeId = sanitizeUuid(contribuyenteId);
  const { rows } = await pool.query<{ email_preferences: Record<string, unknown> | null }>(
    `SELECT email_preferences FROM contribuyentes WHERE entidad_id = $1`,
    [safeId],
  );
  const raw = rows[0]?.email_preferences ?? {};
  return applyDefaults(raw);
}

/**
 * Actualiza las preferencias de un contribuyente. Solo persiste las
 * keys conocidas (filtra extras maliciosos). Merge sobre la columna
 * existente (no sobreescribe keys no enviadas).
 */
export async function setContribuyenteEmailPreferences(
  pool: Pool,
  contribuyenteId: string,
  partial: Partial<EmailPreferences>,
): Promise<EmailPreferences> {
  const safeId = sanitizeUuid(contribuyenteId);
  const merged: Record<string, boolean> = {};
  for (const t of EMAIL_TYPES) {
    if (t in partial) merged[t] = partial[t] === true;
  }

  await pool.query(
    `UPDATE contribuyentes
        SET email_preferences = COALESCE(email_preferences, '{}'::jsonb) || $2::jsonb
      WHERE entidad_id = $1`,
    [safeId, JSON.stringify(merged)],
  );

  return getContribuyenteEmailPreferences(pool, contribuyenteId);
}

/**
 * Lee preferencias para múltiples contribuyentes en una sola query.
 * Útil para la UI de `/configuracion/notificaciones` que lista todos.
 */
export async function getEmailPreferencesPorContribuyente(
  pool: Pool,
): Promise<Array<{ contribuyenteId: string; rfc: string; nombre: string; preferences: EmailPreferences }>> {
  const { rows } = await pool.query<{
    entidad_id: string;
    rfc: string;
    nombre: string;
    email_preferences: Record<string, unknown> | null;
  }>(
    `SELECT c.entidad_id, c.rfc, e.nombre, c.email_preferences
       FROM contribuyentes c
       JOIN entidades_gestionadas e ON e.id = c.entidad_id
      WHERE e.active = true
      ORDER BY e.nombre`,
  );

  return rows.map(r => ({
    contribuyenteId: r.entidad_id,
    rfc: r.rfc,
    nombre: r.nombre,
    preferences: applyDefaults(r.email_preferences ?? {}),
  }));
}
