import type { Pool } from 'pg';
import { prisma } from '../config/database.js';

export async function getAllRegimenes() {
  return prisma.regimen.findMany({
    where: { activo: true },
    orderBy: { clave: 'asc' },
  });
}

export async function getRegimenesIgnorados(tenantId: string) {
  const rows = await prisma.tenantRegimenIgnorado.findMany({
    where: { tenantId },
    include: { regimen: true },
    orderBy: { regimen: { clave: 'asc' } },
  });
  return rows.map(r => r.regimen);
}

export async function getRegimenesIgnoradosClaves(tenantId: string): Promise<string[]> {
  const rows = await prisma.tenantRegimenIgnorado.findMany({
    where: { tenantId },
    include: { regimen: { select: { clave: true } } },
  });
  return rows.map(r => r.regimen.clave);
}

export async function getRegimenesActivos(tenantId: string) {
  const rows = await prisma.tenantRegimenActivo.findMany({
    where: { tenantId },
    include: { regimen: true },
    orderBy: { regimen: { clave: 'asc' } },
  });
  return rows.map(r => r.regimen);
}

export async function getRegimenesActivosClaves(tenantId: string): Promise<string[]> {
  const rows = await prisma.tenantRegimenActivo.findMany({
    where: { tenantId },
    include: { regimen: { select: { clave: true } } },
  });
  return rows.map(r => r.regimen.clave);
}

/**
 * Resuelve las claves de regímenes activos para la alerta de discrepancia.
 * Si hay contribuyenteId, lee de contribuyentes.regimen_fiscal (comma-separated).
 * Si no, combina TenantRegimenActivo (tabla central) con los regímenes de
 * todos los contribuyentes activos del tenant. Esto evita que la alerta
 * aparezca en el correo por-contribuyente pero desaparezca en el dashboard
 * cuando no hay un contribuyente seleccionado.
 */
export async function getRegimenesActivosClavesEfectivos(
  tenantId: string,
  pool: Pool,
  contribuyenteId?: string | null,
): Promise<string[]> {
  if (contribuyenteId) {
    const safeId = contribuyenteId.replace(/[^a-f0-9-]/gi, '');
    const { rows } = await pool.query(
      `SELECT regimen_fiscal FROM contribuyentes WHERE entidad_id = $1`,
      [safeId],
    );
    if (rows.length > 0 && rows[0].regimen_fiscal) {
      return rows[0].regimen_fiscal.split(',').map((c: string) => c.trim()).filter(Boolean);
    }
    // Fallback: si el contribuyente no tiene regimen_fiscal, usamos los del tenant
    // para no perder la alerta si el campo quedó vacío accidentalmente.
    const tenantRegimenes = await getRegimenesActivosClaves(tenantId);
    if (tenantRegimenes.length > 0) return tenantRegimenes;

    const { rows: allRows } = await pool.query(
      `SELECT DISTINCT regimen_fiscal FROM contribuyentes WHERE regimen_fiscal IS NOT NULL AND regimen_fiscal <> ''`,
    );
    const set = new Set<string>();
    for (const row of allRows) {
      if (row.regimen_fiscal) {
        for (const clave of row.regimen_fiscal.split(',')) {
          const trimmed = clave.trim();
          if (trimmed) set.add(trimmed);
        }
      }
    }
    return Array.from(set);
  }

  const tenantRegimenes = await getRegimenesActivosClaves(tenantId);

  // Fallback: si no hay regímenes configurados a nivel tenant, usamos los
  // regímenes de todos los contribuyentes activos del tenant.
  if (tenantRegimenes.length > 0) {
    return tenantRegimenes;
  }

  const { rows } = await pool.query(
    `SELECT DISTINCT regimen_fiscal FROM contribuyentes WHERE regimen_fiscal IS NOT NULL AND regimen_fiscal <> ''`,
  );

  const set = new Set<string>();
  for (const row of rows) {
    if (row.regimen_fiscal) {
      for (const clave of row.regimen_fiscal.split(',')) {
        const trimmed = clave.trim();
        if (trimmed) set.add(trimmed);
      }
    }
  }

  return Array.from(set);
}

export async function setRegimenesActivos(tenantId: string, regimenIds: number[]) {
  await prisma.tenantRegimenActivo.deleteMany({ where: { tenantId } });

  if (regimenIds.length > 0) {
    await prisma.tenantRegimenActivo.createMany({
      data: regimenIds.map(regimenId => ({ tenantId, regimenId })),
    });
  }

  return getRegimenesActivos(tenantId);
}

export async function setRegimenesIgnorados(tenantId: string, regimenIds: number[]) {
  // Delete all existing and re-insert
  await prisma.tenantRegimenIgnorado.deleteMany({ where: { tenantId } });

  if (regimenIds.length > 0) {
    await prisma.tenantRegimenIgnorado.createMany({
      data: regimenIds.map(regimenId => ({ tenantId, regimenId })),
    });
  }

  return getRegimenesIgnorados(tenantId);
}
