/**
 * Diseca cómo se compensa la I PPD con cfdi_tipo_relacion='07' (aplicación
 * de anticipo) en el cálculo de deducciones, evaluando:
 *  - Si NO entra al sumatorio normal (I PUE / P) por ser PPD
 *  - Si entra a la compensación I/07 PPD ↔ E del mismo mes
 *  - Si tiene cfdis_relacionados (qué referencia hacia atrás)
 *  - Si es referenciada por algún CFDI hacia adelante (P, E, otra I)
 *  - Cómo afecta con considerarActivos ON vs OFF
 */
import { prisma, tenantDb } from '../src/config/database.js';

async function main() {
  const t = await prisma.tenant.findFirst({ where: { rfc: 'DESPACHO_MO3NI6U8_B9VGG' } });
  if (!t) { console.log('Patito tenant not found'); return; }
  const pool = await tenantDb.getPool(t.id, t.databaseName);

  const TARGET = '5c874749-748f-11f0-96b1-2b9310891836';
  const RFC = 'TOAH680201RA2';

  // ───────────────────────────────────────────────────────────────────────────
  // 0) Datos del CFDI
  // ───────────────────────────────────────────────────────────────────────────
  const { rows: [c] } = await pool.query(`
    SELECT uuid, type, tipo_comprobante, metodo_pago, forma_pago, uso_cfdi,
           cfdi_tipo_relacion, cfdis_relacionados,
           total_mxn, iva_traslado_mxn, ieps_traslado_mxn,
           rfc_emisor, nombre_emisor, regimen_fiscal_emisor,
           rfc_receptor, nombre_receptor, regimen_fiscal_receptor,
           fecha_emision, fecha_pago_p, status,
           saldo_pendiente_mxn
    FROM cfdis WHERE LOWER(uuid) = LOWER($1)
  `, [TARGET]);

  console.log('═══ CFDI ═══');
  for (const [k, v] of Object.entries(c)) {
    console.log(`  ${k.padEnd(28)} ${v}`);
  }

  // ───────────────────────────────────────────────────────────────────────────
  // 1) ¿Hace referencia hacia atrás (vía cfdis_relacionados)?
  // ───────────────────────────────────────────────────────────────────────────
  console.log('\n═══ Referencias hacia atrás (cfdis_relacionados) ═══');
  if (!c.cfdis_relacionados) {
    console.log('  (ninguna — cfdis_relacionados es NULL)');
  } else {
    const uuids = String(c.cfdis_relacionados).split('|').map((s: string) => s.trim()).filter(Boolean);
    for (const u of uuids) {
      const { rows: [rel] } = await pool.query(`
        SELECT uuid, tipo_comprobante, metodo_pago, total_mxn, fecha_emision, cfdi_tipo_relacion
        FROM cfdis WHERE LOWER(uuid) = LOWER($1)
      `, [u]);
      console.log(`  ${u} →`, rel ?? '(no encontrado)');
    }
  }

  // ───────────────────────────────────────────────────────────────────────────
  // 2) ¿Es referenciada hacia adelante? (P que la pague, E que la cancele, otra I tipo_relacion=07 que sustituya)
  // ───────────────────────────────────────────────────────────────────────────
  console.log('\n═══ CFDIs que referencian a este (hacia adelante) ═══');

  // P que la pagan vía uuid_relacionado
  const { rows: pagos } = await pool.query(`
    SELECT uuid, monto_pago_mxn, fecha_pago_p
    FROM cfdis
    WHERE tipo_comprobante = 'P'
      AND LOWER(uuid_relacionado) = LOWER($1)
      AND status NOT IN ('Cancelado','0')
    ORDER BY fecha_pago_p
  `, [TARGET]);
  console.log(`  P que la pagan (${pagos.length}):`);
  let totalPagado = 0;
  for (const p of pagos) {
    totalPagado += Number(p.monto_pago_mxn || 0);
    console.log(`    ${p.uuid} | $${p.monto_pago_mxn} | ${p.fecha_pago_p}`);
  }
  console.log(`  → Total pagado vía P:  $${totalPagado.toLocaleString('es-MX')}`);
  console.log(`    Total CFDI original: $${c.total_mxn}`);
  console.log(`    Saldo pendiente:     $${c.saldo_pendiente_mxn ?? '?'}`);

  // E que la cancelan vía cfdis_relacionados
  const { rows: ecanc } = await pool.query(`
    SELECT uuid, tipo_comprobante, metodo_pago, total_mxn, cfdi_tipo_relacion, fecha_emision
    FROM cfdis
    WHERE tipo_comprobante = 'E'
      AND cfdis_relacionados IS NOT NULL
      AND LOWER($1) = ANY(string_to_array(LOWER(cfdis_relacionados), '|'))
      AND status NOT IN ('Cancelado','0')
  `, [TARGET]);
  console.log(`\n  E que la referencian (${ecanc.length}):`);
  for (const e of ecanc) {
    console.log(`    ${e.uuid} | total=$${e.total_mxn} | tipo_rel=${e.cfdi_tipo_relacion} | ${e.fecha_emision}`);
  }

  // ───────────────────────────────────────────────────────────────────────────
  // 3) Compensación I/07 PPD ↔ E lado RECEPTOR (mismo mes)
  // ───────────────────────────────────────────────────────────────────────────
  console.log('\n═══ ¿Entra en compensación I/07 PPD ↔ E (mes/año del CFDI)? ═══');

  const fecha = new Date(c.fecha_emision);
  const mesAnio = `${fecha.getFullYear()}-${String(fecha.getMonth() + 1).padStart(2, '0')}`;
  console.log(`  CFDI mes/año:           ${mesAnio}`);
  console.log(`  cfdi_tipo_relacion='07': ${c.cfdi_tipo_relacion === '07' ? '✓ SÍ' : '✗ NO'}`);
  console.log(`  metodo_pago='PPD':       ${c.metodo_pago === 'PPD' ? '✓ SÍ' : '✗ NO'}`);

  if (c.cfdi_tipo_relacion === '07' && c.metodo_pago === 'PPD') {
    // Calcular el aporte que tendría a la compensación (suma de E del mismo mes)
    const { rows: comp } = await pool.query(`
      SELECT
        COALESCE(SUM(
          COALESCE(e.total_mxn, 0)
          - COALESCE(e.iva_traslado_mxn, 0)
          - COALESCE(e.ieps_traslado_mxn, 0)
          - COALESCE(e.impuestos_locales_trasladado_mxn, 0)
        ), 0)::numeric(14,2) AS aporte
      FROM cfdis e
      WHERE e.tipo_comprobante = 'E'
        AND e.metodo_pago = 'PUE'
        AND e.status NOT IN ('Cancelado','0')
        AND UPPER(e.rfc_receptor) = $1
        AND LOWER($2) = ANY(string_to_array(LOWER(e.cfdis_relacionados), '|'))
        AND date_trunc('month', e.fecha_emision) = date_trunc('month', $3::timestamp)
    `, [RFC, TARGET, c.fecha_emision]);
    console.log(`\n  Aporte a la compensación (suma E mismo mes): $${comp[0].aporte}`);
    if (Number(comp[0].aporte) > 0) {
      console.log(`  → SÍ entra en compensación`);
    } else {
      console.log(`  → NO entra (no hay E en mismo mes que la referencien)`);
    }
  }

  // ───────────────────────────────────────────────────────────────────────────
  // 4) ¿Aparece en el cálculo "I PUE recibidas" o "P recibidos"?
  // ───────────────────────────────────────────────────────────────────────────
  console.log('\n═══ ¿Aparece en el cálculo directo? ═══');
  console.log(`  I PUE recibidas requiere: tipo_comprobante='I' AND metodo_pago='PUE'`);
  console.log(`  Este CFDI: tipo_comprobante='${c.tipo_comprobante}', metodo_pago='${c.metodo_pago}'`);
  console.log(`  → ${c.tipo_comprobante === 'I' && c.metodo_pago === 'PUE' ? '✓ SÍ entra' : '✗ NO entra'} (es ${c.tipo_comprobante} ${c.metodo_pago})`);

  // ───────────────────────────────────────────────────────────────────────────
  // 5) Predicado de filtro de activos
  // ───────────────────────────────────────────────────────────────────────────
  console.log('\n═══ Predicado de filtro de activos sobre este CFDI ═══');
  const ACTIVOS = "('I01','I02','I03','I04','I05','I06','I07','I08')";
  const t1 = await pool.query(`
    SELECT
      (tipo_comprobante = 'I' AND uso_cfdi IN ${ACTIVOS}) AS regla1_directo,
      (tipo_comprobante = 'P' AND EXISTS (
        SELECT 1 FROM cfdis i_act
        WHERE LOWER(i_act.uuid) = LOWER(cfdis.uuid_relacionado)
          AND i_act.tipo_comprobante = 'I'
          AND i_act.uso_cfdi IN ${ACTIVOS}
      )) AS regla2,
      (tipo_comprobante = 'E' AND cfdis.cfdis_relacionados IS NOT NULL AND EXISTS (
        SELECT 1 FROM cfdis r_act
        WHERE LOWER(r_act.uuid) = ANY(string_to_array(LOWER(cfdis.cfdis_relacionados), '|'))
          AND (r_act.tipo_comprobante = 'I' AND r_act.uso_cfdi IN ${ACTIVOS})
      )) AS regla3
    FROM cfdis WHERE LOWER(uuid) = LOWER($1)
  `, [TARGET]);
  console.log(`  regla1 (I directo activo):    ${t1.rows[0].regla1_directo ? '🔴 TRUE' : '🟢 FALSE'}`);
  console.log(`  regla2 (P paga I activo):     ${t1.rows[0].regla2 ? '🔴 TRUE' : '🟢 FALSE'}`);
  console.log(`  regla3 (E ref. I/P activo):   ${t1.rows[0].regla3 ? '🔴 TRUE' : '🟢 FALSE'}`);
  const filtrado = t1.rows[0].regla1_directo || t1.rows[0].regla2 || t1.rows[0].regla3;
  console.log(`  → Si "Considerar activos" OFF → ${filtrado ? '🔴 EXCLUIDO' : '🟢 PASA'}`);

  await prisma.$disconnect();
}

main().catch(e => { console.error(e); process.exit(1); });
