/**
 * Amplía la inspección: lista TODOS los CFDIs de mayo-2025 donde Horux 360
 * aparece como emisor o receptor, marcando cuáles entran al bucket ingresos
 * y cuáles no + por qué.
 */
import { prisma, tenantDb } from '../src/config/database.js';
import { resolveContribuyenteContext } from '../src/utils/contribuyente-context.js';

const TENANT_RFC = 'DESPACHO_MO3NI6U8_B9VGG';
const CONTRIB_ID = 'b3761db6-0b8d-4251-8078-4ddc31e9c75b';
const FI = '2025-05-01';
const FF = '2025-05-31';

async function main() {
  const tenant = await prisma.tenant.findFirst({
    where: { rfc: TENANT_RFC }, select: { id: true, databaseName: true },
  });
  if (!tenant) return;
  const pool = await tenantDb.getPool(tenant.id, tenant.databaseName);
  const ctx = await resolveContribuyenteContext(pool, tenant.id, CONTRIB_ID);

  console.log(`\n=== TODOS los CFDIs de Horux 360 en mayo-2025 (como emisor o receptor) ===\n`);

  const { rows } = await pool.query(
    `SELECT uuid, type, tipo_comprobante, metodo_pago, status,
            regimen_fiscal_emisor, regimen_fiscal_receptor,
            rfc_emisor, rfc_receptor, nombre_receptor, nombre_emisor,
            total_mxn, monto_pago_mxn, cfdi_tipo_relacion, fecha_emision, source
       FROM cfdis
      WHERE ((${ctx.esEmisor}) OR (${ctx.esReceptor}))
        AND fecha_emision >= $1::date
        AND fecha_emision < ($2::date + interval '1 day')
      ORDER BY fecha_emision, tipo_comprobante, total_mxn DESC`,
    [FI, FF],
  );

  console.log(`Total CFDIs encontrados: ${rows.length}\n`);

  const buckets: Record<string, any[]> = {
    ingresosG1: [],
    ingresosG3: [],
    ingresosSueldos: [],
    noIncluye_canceladoOinvalido: [],
    noIncluye_regimenFuera: [],
    noIncluye_comoReceptor: [],
    noIncluye_otroMotivo: [],
  };

  const G1 = ['606', '612', '621', '625', '626'];
  const G3 = ['601', '603', '607', '608', '610', '611', '614', '615', '620', '622', '623', '624'];

  for (const r of rows) {
    const cancel = ['Cancelado', '0'].includes(r.status);
    const esEmisorRow = String(r.rfc_emisor).toUpperCase() === 'HTS240708LJA';
    const regE = r.regimen_fiscal_emisor;
    const regR = r.regimen_fiscal_receptor;

    if (cancel) { buckets.noIncluye_canceladoOinvalido.push(r); continue; }

    if (esEmisorRow) {
      if (G1.includes(regE)) {
        if ((r.tipo_comprobante === 'I' && r.metodo_pago === 'PUE') ||
            (r.tipo_comprobante === 'P') ||
            (r.tipo_comprobante === 'E' && r.metodo_pago === 'PUE')) {
          buckets.ingresosG1.push(r); continue;
        }
      }
      if (G3.includes(regE)) {
        if ((r.tipo_comprobante === 'I' && ['PUE', 'PPD'].includes(r.metodo_pago)) ||
            (r.tipo_comprobante === 'E' && r.metodo_pago === 'PUE')) {
          buckets.ingresosG3.push(r); continue;
        }
      }
      if (!G1.includes(regE) && !G3.includes(regE)) {
        buckets.noIncluye_regimenFuera.push({ ...r, reason: `emisor régimen ${regE} fuera de grupo` });
        continue;
      }
      buckets.noIncluye_otroMotivo.push({ ...r, reason: `emisor tipo=${r.tipo_comprobante}/${r.metodo_pago} no matchea` });
      continue;
    }

    // No emisor → receptor
    if (r.tipo_comprobante === 'N' && r.metodo_pago === 'PUE' && regR === '605') {
      buckets.ingresosSueldos.push(r); continue;
    }
    buckets.noIncluye_comoReceptor.push({ ...r, reason: 'es receptor, no cuenta como ingreso (salvo N/605)' });
  }

  const fmt = (n: any) => Number(n || 0).toFixed(2);

  for (const [name, list] of Object.entries(buckets)) {
    if (list.length === 0) continue;
    console.log(`\n--- ${name} (${list.length}) ---`);
    for (const r of list) {
      const fe = r.fecha_emision?.toISOString?.()?.slice(0, 10) || r.fecha_emision;
      const reason = r.reason ? `  | ${r.reason}` : '';
      console.log(`  ${fe}  ${r.tipo_comprobante}/${r.metodo_pago || '-'}  status=${r.status}  regE=${r.regimen_fiscal_emisor} regR=${r.regimen_fiscal_receptor}  ${r.rfc_emisor}→${r.rfc_receptor}  total=${fmt(r.total_mxn)}  mp=${fmt(r.monto_pago_mxn)}  ${r.uuid.substring(0,8)}${reason}`);
    }
  }

  await prisma.$disconnect();
}

main().catch(async e => { console.error(e); await prisma.$disconnect().catch(() => {}); process.exit(1); });
