import type { Pool } from 'pg';
import type { EstadoResultados, EstadoResultadosDetallado, FlujoEfectivo, ComparativoPeriodos, ConcentradoRfc } from '@horux/shared';
import { calcularIngresosPorRegimen, calcularEgresosPorRegimen } from './dashboard.service.js';
import ExcelJS from 'exceljs';

/**
 * Resuelve condiciones `esEmisor` / `esReceptor` para un contribuyente
 * usando su RFC. Reemplaza el par `type = 'X' AND contribuyente_id = Y`.
 * Si no hay contribuyente, retorna fallback a `type`.
 */
async function resolveEmisorReceptor(
  pool: Pool,
  contribuyenteId?: string | null,
): Promise<{ esEmisor: string; esReceptor: string }> {
  if (!contribuyenteId) {
    return { esEmisor: `type = 'EMITIDO'`, esReceptor: `type = 'RECIBIDO'` };
  }
  const safeId = contribuyenteId.replace(/[^a-f0-9-]/gi, '');
  if (!safeId) return { esEmisor: `type = 'EMITIDO'`, esReceptor: `type = 'RECIBIDO'` };
  const { rows } = await pool.query<{ rfc: string | null }>(
    `SELECT rfc FROM contribuyentes WHERE entidad_id = $1`,
    [safeId],
  );
  const rfc = (rows[0]?.rfc || '').replace(/[^A-Z0-9]/gi, '').toUpperCase();
  if (!rfc) {
    return {
      esEmisor: `type = 'EMITIDO' AND contribuyente_id = '${safeId}'`,
      esReceptor: `type = 'RECIBIDO' AND contribuyente_id = '${safeId}'`,
    };
  }
  return {
    esEmisor: `UPPER(rfc_emisor) = '${rfc}'`,
    esReceptor: `UPPER(rfc_receptor) = '${rfc}'`,
  };
}

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

function toNumber(value: unknown): number {
  if (value === null || value === undefined) return 0;
  if (typeof value === 'number') return value;
  if (typeof value === 'bigint') return Number(value);
  if (typeof value === 'string') return parseFloat(value) || 0;
  if (typeof value === 'object' && value !== null && 'toNumber' in value) {
    return (value as { toNumber: () => number }).toNumber();
  }
  return Number(value) || 0;
}

export async function getEstadoResultados(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  tenantId: string,
  contribuyenteId?: string | null,
): Promise<EstadoResultados> {
  // Totales usando la misma lógica del dashboard
  const ingresosData = await calcularIngresosPorRegimen(pool, tenantId, fechaInicio, fechaFin, undefined, undefined, undefined, contribuyenteId);
  const egresosData = await calcularEgresosPorRegimen(pool, tenantId, fechaInicio, fechaFin, undefined, undefined, undefined, contribuyenteId);

  const totalIngresos = ingresosData.total;
  const totalEgresos = egresosData.total;
  const utilidadBruta = totalIngresos - totalEgresos;

  // Desglose por régimen como conceptos
  const ingresosConceptos = ingresosData.porRegimen.map(r => ({
    concepto: `${r.regimenClave} - ${r.regimenDescripcion}`,
    monto: r.monto,
  }));

  const egresosConceptos = egresosData.porRegimen.map(r => ({
    concepto: `${r.regimenClave} - ${r.regimenDescripcion}`,
    monto: r.monto,
  }));

  return {
    periodo: { inicio: fechaInicio, fin: fechaFin },
    ingresos: ingresosConceptos,
    egresos: egresosConceptos,
    totalIngresos,
    totalEgresos,
    utilidadBruta,
    impuestos: 0,
    utilidadNeta: utilidadBruta,
  };
}

export async function getFlujoEfectivo(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  contribuyenteId?: string | null,
): Promise<FlujoEfectivo> {
  const VIGENTE = `status NOT IN ('Cancelado', '0')`;
  const RANGO = `COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') >= $1::date AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < ($2::date + interval '1 day')`;
  const RANGO_PAGO = `(fecha_pago_p - interval '1 hour') >= $1::date AND (fecha_pago_p - interval '1 hour') < ($2::date + interval '1 day')`;
  const { esEmisor, esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);

  const { rows: entradasPUE } = await pool.query(`
    SELECT TO_CHAR(COALESCE(fecha_efectiva, fecha_emision - interval '1 hour'), 'YYYY-MM') as mes, COALESCE(SUM(total_mxn), 0) as total
    FROM cfdis
    WHERE ${esEmisor} AND tipo_comprobante = 'I' AND metodo_pago = 'PUE'
      AND ${VIGENTE} AND ${RANGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  const { rows: entradasPago } = await pool.query(`
    SELECT TO_CHAR(fecha_pago_p - interval '1 hour', 'YYYY-MM') as mes, COALESCE(SUM(monto_pago_mxn), 0) as total
    FROM cfdis
    WHERE ${esEmisor} AND tipo_comprobante = 'P'
      AND ${VIGENTE} AND ${RANGO_PAGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  const { rows: entradasNC } = await pool.query(`
    SELECT TO_CHAR(COALESCE(fecha_efectiva, fecha_emision - interval '1 hour'), 'YYYY-MM') as mes, COALESCE(SUM(total_mxn), 0) as total
    FROM cfdis
    WHERE ${esEmisor} AND tipo_comprobante = 'E' AND metodo_pago = 'PUE'
      AND COALESCE(cfdi_tipo_relacion, '') <> '07'
      AND ${VIGENTE} AND ${RANGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  const { rows: salidasPUE } = await pool.query(`
    SELECT TO_CHAR(COALESCE(fecha_efectiva, fecha_emision - interval '1 hour'), 'YYYY-MM') as mes, COALESCE(SUM(total_mxn), 0) as total
    FROM cfdis
    WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago = 'PUE'
      AND ${VIGENTE} AND ${RANGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  const { rows: salidasPago } = await pool.query(`
    SELECT TO_CHAR(fecha_pago_p - interval '1 hour', 'YYYY-MM') as mes, COALESCE(SUM(monto_pago_mxn), 0) as total
    FROM cfdis
    WHERE ${esReceptor} AND tipo_comprobante = 'P'
      AND ${VIGENTE} AND ${RANGO_PAGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  const { rows: salidasNC } = await pool.query(`
    SELECT TO_CHAR(COALESCE(fecha_efectiva, fecha_emision - interval '1 hour'), 'YYYY-MM') as mes, COALESCE(SUM(total_mxn), 0) as total
    FROM cfdis
    WHERE ${esReceptor} AND tipo_comprobante = 'E' AND metodo_pago = 'PUE'
      AND COALESCE(cfdi_tipo_relacion, '') <> '07'
      AND ${VIGENTE} AND ${RANGO}
    GROUP BY mes ORDER BY mes
  `, [fechaInicio, fechaFin]);

  // Combinar por mes
  const mesesSet = new Set<string>();
  [...entradasPUE, ...entradasPago, ...entradasNC, ...salidasPUE, ...salidasPago, ...salidasNC].forEach((r: any) => mesesSet.add(r.mes));
  const mesesOrdenados = Array.from(mesesSet).sort();

  const get = (rows: any[], mes: string) => toNumber(rows.find((r: any) => r.mes === mes)?.total);

  const entradas = mesesOrdenados.map(mes => ({
    concepto: mes,
    monto: get(entradasPUE, mes) + get(entradasPago, mes) - get(entradasNC, mes),
  }));

  const salidas = mesesOrdenados.map(mes => ({
    concepto: mes,
    monto: get(salidasPUE, mes) + get(salidasPago, mes) - get(salidasNC, mes),
  }));

  const totalEntradas = entradas.reduce((s, e) => s + e.monto, 0);
  const totalSalidas = salidas.reduce((s, e) => s + e.monto, 0);

  return {
    periodo: { inicio: fechaInicio, fin: fechaFin },
    saldoInicial: 0,
    entradas,
    salidas,
    totalEntradas,
    totalSalidas,
    flujoNeto: totalEntradas - totalSalidas,
    saldoFinal: totalEntradas - totalSalidas,
  };
}

/**
 * Calcula entradas/salidas de un año completo mes a mes con la lógica de flujo de efectivo.
 */
async function calcularFlujoPorMes(pool: Pool, año: number, contribuyenteId?: string | null): Promise<{ entradas: number[]; salidas: number[] }> {
  const VIGENTE = `status NOT IN ('Cancelado', '0')`;
  const fi = `${año}-01-01`;
  const ff = `${año}-12-31`;
  const RANGO = `COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') >= $1::date AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < ($2::date + interval '1 day')`;
  const RANGO_PAGO = `(fecha_pago_p - interval '1 hour') >= $1::date AND (fecha_pago_p - interval '1 hour') < ($2::date + interval '1 day')`;
  const { esEmisor, esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);

  const q = async (lado: 'EMITIDO' | 'RECIBIDO', tc: string, campo: string, mp?: string) => {
    const mpF = mp ? `AND metodo_pago = '${mp}'` : '';
    const fechaCol = tc === 'P' ? 'fecha_pago_p' : 'fecha_emision';
    const rango = tc === 'P' ? RANGO_PAGO : RANGO;
    const noAnticipo = tc === 'E' ? `AND COALESCE(cfdi_tipo_relacion, '') <> '07'` : '';
    const ladoCond = lado === 'EMITIDO' ? esEmisor : esReceptor;
    const { rows } = await pool.query(`
      SELECT EXTRACT(MONTH FROM COALESCE(fecha_efectiva, ${fechaCol} - interval '1 hour'))::int as mes, COALESCE(SUM(${campo}), 0) as total
      FROM cfdis
      WHERE ${ladoCond} AND tipo_comprobante = '${tc}' ${mpF} ${noAnticipo} AND ${VIGENTE} AND ${rango}
      GROUP BY mes
    `, [fi, ff]);
    const map = new Map<number, number>();
    for (const r of rows) map.set(r.mes, Number(r.total));
    return map;
  };

  const [ePUE, ePago, eNC, sPUE, sPago, sNC] = await Promise.all([
    q('EMITIDO', 'I', 'total_mxn', 'PUE'),
    q('EMITIDO', 'P', 'monto_pago_mxn'),
    q('EMITIDO', 'E', 'total_mxn', 'PUE'),
    q('RECIBIDO', 'I', 'total_mxn', 'PUE'),
    q('RECIBIDO', 'P', 'monto_pago_mxn'),
    q('RECIBIDO', 'E', 'total_mxn', 'PUE'),
  ]);

  const g = (map: Map<number, number>, m: number) => map.get(m) || 0;

  const entradas: number[] = [];
  const salidas: number[] = [];

  for (let m = 1; m <= 12; m++) {
    entradas.push(g(ePUE, m) + g(ePago, m) - g(eNC, m));
    salidas.push(g(sPUE, m) + g(sPago, m) - g(sNC, m));
  }

  return { entradas, salidas };
}

export async function getComparativo(
  pool: Pool,
  año: number,
  contribuyenteId?: string | null,
): Promise<ComparativoPeriodos> {
  const [actual, anterior] = await Promise.all([
    calcularFlujoPorMes(pool, año, contribuyenteId),
    calcularFlujoPorMes(pool, año - 1, contribuyenteId),
  ]);

  const meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'];
  const utilidad = actual.entradas.map((e, i) => e - actual.salidas[i]);

  const totalActualIng = actual.entradas.reduce((a, b) => a + b, 0);
  const totalAnteriorIng = anterior.entradas.reduce((a, b) => a + b, 0);
  const totalActualEgr = actual.salidas.reduce((a, b) => a + b, 0);
  const totalAnteriorEgr = anterior.salidas.reduce((a, b) => a + b, 0);

  return {
    periodos: meses,
    ingresos: actual.entradas,
    egresos: actual.salidas,
    utilidad,
    variacionIngresos: totalAnteriorIng > 0 ? ((totalActualIng - totalAnteriorIng) / totalAnteriorIng) * 100 : 0,
    variacionEgresos: totalAnteriorEgr > 0 ? ((totalActualEgr - totalAnteriorEgr) / totalAnteriorEgr) * 100 : 0,
    variacionUtilidad: 0,
  };
}

export async function getConcentradoRfc(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  tipo: 'cliente' | 'proveedor',
  contribuyenteId?: string | null,
): Promise<ConcentradoRfc[]> {
  const { esEmisor, esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);

  if (tipo === 'cliente') {
    const { rows: data } = await pool.query(`
      SELECT rfc_receptor as rfc, nombre_receptor as nombre,
        'cliente' as tipo,
        SUM(total_mxn) as "totalFacturado",
        SUM(iva_traslado_mxn) as "totalIva",
        COUNT(*)::int as "cantidadCfdis"
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'I' AND status NOT IN ('Cancelado', '0')
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') BETWEEN $1::date AND $2::date
      GROUP BY rfc_receptor, nombre_receptor
      ORDER BY "totalFacturado" DESC
    `, [fechaInicio, fechaFin]);
    return data.map((d: any) => ({
      rfc: d.rfc,
      nombre: d.nombre,
      tipo: 'cliente' as const,
      totalFacturado: toNumber(d.totalFacturado),
      totalIva: toNumber(d.totalIva),
      cantidadCfdis: d.cantidadCfdis
    }));
  } else {
    const { rows: data } = await pool.query(`
      SELECT rfc_emisor as rfc, nombre_emisor as nombre,
        'proveedor' as tipo,
        SUM(total_mxn) as "totalFacturado",
        SUM(iva_traslado_mxn) as "totalIva",
        COUNT(*)::int as "cantidadCfdis"
      FROM cfdis
      WHERE ${esReceptor} AND tipo_comprobante = 'I' AND status NOT IN ('Cancelado', '0')
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') BETWEEN $1::date AND $2::date
      GROUP BY rfc_emisor, nombre_emisor
      ORDER BY "totalFacturado" DESC
    `, [fechaInicio, fechaFin]);
    return data.map((d: any) => ({
      rfc: d.rfc,
      nombre: d.nombre,
      tipo: 'proveedor' as const,
      totalFacturado: toNumber(d.totalFacturado),
      totalIva: toNumber(d.totalIva),
      cantidadCfdis: d.cantidadCfdis
    }));
  }
}

export interface CuentasPendientes {
  cantidadCfdis: number;
  saldoTotal: number;
  detalle: { rfc: string; nombre: string; cantidad: number; saldo: number }[];
}

export async function getCuentasXPagar(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  regimen?: string,
  contribuyenteId?: string | null,
): Promise<CuentasPendientes> {
  const regimenFilter = regimen ? `AND regimen_fiscal_receptor = '${regimen}'` : '';
  const { esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);

  const { rows } = await pool.query(`
    SELECT
      rfc_emisor as rfc,
      nombre_emisor as nombre,
      COUNT(*)::int as cantidad,
      COALESCE(SUM(COALESCE(saldo_pendiente_mxn, total_mxn)), 0) as saldo
    FROM cfdis
    WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago = 'PPD'
      AND status NOT IN ('Cancelado', '0')
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') >= $1::date
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < ($2::date + interval '1 day')
      AND COALESCE(saldo_pendiente_mxn, total_mxn) > 0.01
      ${regimenFilter}
    GROUP BY rfc_emisor, nombre_emisor
    ORDER BY saldo DESC
  `, [fechaInicio, fechaFin]);

  const detalle = rows.map((r: any) => ({
    rfc: r.rfc,
    nombre: r.nombre,
    cantidad: r.cantidad,
    saldo: toNumber(r.saldo),
  }));

  return {
    cantidadCfdis: detalle.reduce((s, d) => s + d.cantidad, 0),
    saldoTotal: detalle.reduce((s, d) => s + d.saldo, 0),
    detalle,
  };
}

// ─────────────────────────────────────────────────────────────────────────────
// Estado de Resultados Detallado (contable)
// ─────────────────────────────────────────────────────────────────────────────

const VIGENTE_ER = `status NOT IN ('Cancelado', '0')`;
const RANGO_FECHA = `COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') >= $1::date AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < ($2::date + interval '1 day')`;
const BASE_MONTO = `COALESCE(subtotal_mxn, 0) - COALESCE(descuento_mxn, 0)`;

function sameDateLastYear(dateStr: string): string {
  const d = new Date(dateStr + 'T00:00:00');
  d.setFullYear(d.getFullYear() - 1);
  return d.toISOString().split('T')[0];
}

function buildRegimenFilter(regimen?: string | null, campo: 'emisor' | 'receptor' = 'emisor'): string {
  if (!regimen) return '';
  const safe = regimen.replace(/[^0-9]/g, '').slice(0, 3);
  if (!safe) return '';
  const col = campo === 'emisor' ? 'regimen_fiscal_emisor' : 'regimen_fiscal_receptor';
  return `AND ${col} = '${safe}'`;
}

async function calcularLineaEstadoResultados(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  esEmisor: string,
  esReceptor: string,
  regimen?: string | null,
): Promise<{
  ventas: number;
  devoluciones: number;
  costoVentas: number;
  gastosOperativosRecibidos: number;
  gastosOperativosNomina: number;
}> {
  const rfEmisor = buildRegimenFilter(regimen, 'emisor');
  const rfReceptor = buildRegimenFilter(regimen, 'receptor');

  const anticipoExcl = `
    AND NOT (uso_cfdi = 'P01')
    AND NOT EXISTS (
      SELECT 1 FROM cfdi_conceptos cc
      WHERE cc.cfdi_id = cfdis.id AND cc.clave_prod_serv = '84111506'
    )
  `;

  const [ventasR, devolR, costoR, gastosRecR, nominaR] = await Promise.all([
    // Ventas
    pool.query<{ monto: string }>(`
      SELECT COALESCE(SUM(${BASE_MONTO}), 0) as monto
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${anticipoExcl}
        ${rfEmisor}
    `, [fechaInicio, fechaFin]),

    // Devoluciones
    pool.query<{ monto: string }>(`
      SELECT COALESCE(SUM(${BASE_MONTO}), 0) as monto
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'E'
        AND COALESCE(cfdi_tipo_relacion, '') IN ('01', '03')
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfEmisor}
    `, [fechaInicio, fechaFin]),

    // Costo de ventas
    pool.query<{ monto: string }>(`
      SELECT COALESCE(SUM(${BASE_MONTO}), 0) as monto
      FROM cfdis
      WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
        AND uso_cfdi = 'G01'
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfReceptor}
    `, [fechaInicio, fechaFin]),

    // Gastos operativos (recibidos, excluyendo G01)
    pool.query<{ monto: string }>(`
      SELECT COALESCE(SUM(${BASE_MONTO}), 0) as monto
      FROM cfdis
      WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
        AND (uso_cfdi != 'G01' OR uso_cfdi IS NULL)
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfReceptor}
    `, [fechaInicio, fechaFin]),

    // Gastos operativos (nómina emitida)
    pool.query<{ monto: string }>(`
      SELECT COALESCE(SUM(total_mxn), 0) as monto
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'N'
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfEmisor}
    `, [fechaInicio, fechaFin]),
  ]);

  return {
    ventas: toNumber(ventasR.rows[0]?.monto),
    devoluciones: toNumber(devolR.rows[0]?.monto),
    costoVentas: toNumber(costoR.rows[0]?.monto),
    gastosOperativosRecibidos: toNumber(gastosRecR.rows[0]?.monto),
    gastosOperativosNomina: toNumber(nominaR.rows[0]?.monto),
  };
}

export async function getEstadoResultadosDetallado(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  _tenantId: string,
  contribuyenteId?: string | null,
  regimen?: string | null,
): Promise<EstadoResultadosDetallado> {
  const { esEmisor, esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);

  const [actual, anterior] = await Promise.all([
    calcularLineaEstadoResultados(pool, fechaInicio, fechaFin, esEmisor, esReceptor, regimen),
    calcularLineaEstadoResultados(pool, sameDateLastYear(fechaInicio), sameDateLastYear(fechaFin), esEmisor, esReceptor, regimen),
  ]);

  function build(d: typeof actual) {
    const ventasNetas = d.ventas - d.devoluciones;
    const utilidadBruta = ventasNetas - d.costoVentas;
    const gastosOperativos = d.gastosOperativosRecibidos + d.gastosOperativosNomina;
    const utilidadOperacion = utilidadBruta - gastosOperativos;
    return { ventasNetas, utilidadBruta, gastosOperativos, utilidadOperacion };
  }

  const a = build(actual);
  const ant = build(anterior);

  return {
    periodo: { inicio: fechaInicio, fin: fechaFin },
    ventas: actual.ventas,
    devoluciones: actual.devoluciones,
    ventasNetas: a.ventasNetas,
    costoVentas: actual.costoVentas,
    utilidadBruta: a.utilidadBruta,
    gastosOperativos: a.gastosOperativos,
    utilidadOperacion: a.utilidadOperacion,
    anterior: {
      ventas: anterior.ventas,
      devoluciones: anterior.devoluciones,
      ventasNetas: ant.ventasNetas,
      costoVentas: anterior.costoVentas,
      utilidadBruta: ant.utilidadBruta,
      gastosOperativos: ant.gastosOperativos,
      utilidadOperacion: ant.utilidadOperacion,
    },
  };
}

// ─────────────────────────────────────────────────────────────────────────────
// Drill-down del Estado de Resultados
// ─────────────────────────────────────────────────────────────────────────────

export interface DrillDownResumenItem {
  rfc: string;
  nombre: string;
  cantidad: number;
  monto: number;
}

export interface DrillDownCfdiItem {
  id: number;
  uuid: string;
  tipoComprobante: string;
  fechaEmision: string;
  rfcEmisor: string;
  nombreEmisor: string;
  rfcReceptor: string;
  nombreReceptor: string;
  monto: number;
  metodoPago: string | null;
  regimenFiscalEmisor: string | null;
  regimenFiscalReceptor: string | null;
}

export async function getEstadoResultadosDrillDown(
  pool: Pool,
  categoria: string,
  fechaInicio: string,
  fechaFin: string,
  contribuyenteId?: string | null,
  regimen?: string | null,
  rfc?: string | null,
): Promise<DrillDownResumenItem[] | DrillDownCfdiItem[]> {
  const { esEmisor, esReceptor } = await resolveEmisorReceptor(pool, contribuyenteId);
  const rfEmisor = buildRegimenFilter(regimen, 'emisor');
  const rfReceptor = buildRegimenFilter(regimen, 'receptor');

  const anticipoExcl = `
    AND NOT (uso_cfdi = 'P01')
    AND NOT EXISTS (
      SELECT 1 FROM cfdi_conceptos cc
      WHERE cc.cfdi_id = cfdis.id AND cc.clave_prod_serv = '84111506'
    )
  `;

  if (categoria === 'ventas') {
    if (!rfc) {
      const { rows } = await pool.query(`
        SELECT rfc_receptor as rfc, nombre_receptor as nombre,
          COUNT(*)::int as cantidad,
          COALESCE(SUM(${BASE_MONTO}), 0) as monto
        FROM cfdis
        WHERE ${esEmisor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
          AND ${VIGENTE_ER} AND ${RANGO_FECHA}
          ${anticipoExcl}
          ${rfEmisor}
        GROUP BY rfc_receptor, nombre_receptor
        ORDER BY monto DESC
      `, [fechaInicio, fechaFin]);
      return rows.map((r: any) => ({ rfc: r.rfc, nombre: r.nombre, cantidad: r.cantidad, monto: toNumber(r.monto) }));
    }
    const { rows } = await pool.query(`
      SELECT id, uuid, tipo_comprobante as "tipoComprobante", fecha_emision as "fechaEmision",
        rfc_emisor as "rfcEmisor", nombre_emisor as "nombreEmisor",
        rfc_receptor as "rfcReceptor", nombre_receptor as "nombreReceptor",
        (${BASE_MONTO})::float as monto,
        metodo_pago as "metodoPago",
        regimen_fiscal_emisor as "regimenFiscalEmisor",
        regimen_fiscal_receptor as "regimenFiscalReceptor"
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${anticipoExcl}
        ${rfEmisor}
        AND rfc_receptor = $3
      ORDER BY fecha_emision DESC
    `, [fechaInicio, fechaFin, rfc]);
    return rows as DrillDownCfdiItem[];
  }

  if (categoria === 'devoluciones') {
    if (!rfc) {
      const { rows } = await pool.query(`
        SELECT rfc_receptor as rfc, nombre_receptor as nombre,
          COUNT(*)::int as cantidad,
          COALESCE(SUM(${BASE_MONTO}), 0) as monto
        FROM cfdis
        WHERE ${esEmisor} AND tipo_comprobante = 'E'
          AND COALESCE(cfdi_tipo_relacion, '') IN ('01', '03')
          AND ${VIGENTE_ER} AND ${RANGO_FECHA}
          ${rfEmisor}
        GROUP BY rfc_receptor, nombre_receptor
        ORDER BY monto DESC
      `, [fechaInicio, fechaFin]);
      return rows.map((r: any) => ({ rfc: r.rfc, nombre: r.nombre, cantidad: r.cantidad, monto: toNumber(r.monto) }));
    }
    const { rows } = await pool.query(`
      SELECT id, uuid, tipo_comprobante as "tipoComprobante", fecha_emision as "fechaEmision",
        rfc_emisor as "rfcEmisor", nombre_emisor as "nombreEmisor",
        rfc_receptor as "rfcReceptor", nombre_receptor as "nombreReceptor",
        (${BASE_MONTO})::float as monto,
        metodo_pago as "metodoPago",
        regimen_fiscal_emisor as "regimenFiscalEmisor",
        regimen_fiscal_receptor as "regimenFiscalReceptor"
      FROM cfdis
      WHERE ${esEmisor} AND tipo_comprobante = 'E'
        AND COALESCE(cfdi_tipo_relacion, '') IN ('01', '03')
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfEmisor}
        AND rfc_receptor = $3
      ORDER BY fecha_emision DESC
    `, [fechaInicio, fechaFin, rfc]);
    return rows as DrillDownCfdiItem[];
  }

  if (categoria === 'costo-ventas') {
    if (!rfc) {
      const { rows } = await pool.query(`
        SELECT rfc_emisor as rfc, nombre_emisor as nombre,
          COUNT(*)::int as cantidad,
          COALESCE(SUM(${BASE_MONTO}), 0) as monto
        FROM cfdis
        WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
          AND uso_cfdi = 'G01'
          AND ${VIGENTE_ER} AND ${RANGO_FECHA}
          ${rfReceptor}
        GROUP BY rfc_emisor, nombre_emisor
        ORDER BY monto DESC
      `, [fechaInicio, fechaFin]);
      return rows.map((r: any) => ({ rfc: r.rfc, nombre: r.nombre, cantidad: r.cantidad, monto: toNumber(r.monto) }));
    }
    const { rows } = await pool.query(`
      SELECT id, uuid, tipo_comprobante as "tipoComprobante", fecha_emision as "fechaEmision",
        rfc_emisor as "rfcEmisor", nombre_emisor as "nombreEmisor",
        rfc_receptor as "rfcReceptor", nombre_receptor as "nombreReceptor",
        (${BASE_MONTO})::float as monto,
        metodo_pago as "metodoPago",
        regimen_fiscal_emisor as "regimenFiscalEmisor",
        regimen_fiscal_receptor as "regimenFiscalReceptor"
      FROM cfdis
      WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
        AND uso_cfdi = 'G01'
        AND ${VIGENTE_ER} AND ${RANGO_FECHA}
        ${rfReceptor}
        AND rfc_emisor = $3
      ORDER BY fecha_emision DESC
    `, [fechaInicio, fechaFin, rfc]);
    return rows as DrillDownCfdiItem[];
  }

  if (categoria === 'gastos-operativos') {
    if (!rfc) {
      const [{ rows: recRows }, { rows: nomRows }] = await Promise.all([
        pool.query(`
          SELECT rfc_emisor as rfc, nombre_emisor as nombre,
            COUNT(*)::int as cantidad,
            COALESCE(SUM(${BASE_MONTO}), 0) as monto
          FROM cfdis
          WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
            AND (uso_cfdi != 'G01' OR uso_cfdi IS NULL)
            AND ${VIGENTE_ER} AND ${RANGO_FECHA}
            ${rfReceptor}
          GROUP BY rfc_emisor, nombre_emisor
          ORDER BY monto DESC
        `, [fechaInicio, fechaFin]),
        pool.query(`
          SELECT rfc_receptor as rfc, nombre_receptor as nombre,
            COUNT(*)::int as cantidad,
            COALESCE(SUM(total_mxn), 0) as monto
          FROM cfdis
          WHERE ${esEmisor} AND tipo_comprobante = 'N'
            AND ${VIGENTE_ER} AND ${RANGO_FECHA}
            ${rfEmisor}
          GROUP BY rfc_receptor, nombre_receptor
          ORDER BY monto DESC
        `, [fechaInicio, fechaFin]),
      ]);
      const map = new Map<string, DrillDownResumenItem>();
      for (const r of recRows) {
        const key = r.rfc as string;
        const existing = map.get(key);
        if (existing) {
          existing.cantidad += (r.cantidad as number);
          existing.monto += toNumber(r.monto);
        } else {
          map.set(key, { rfc: key, nombre: r.nombre as string, cantidad: r.cantidad as number, monto: toNumber(r.monto) });
        }
      }
      for (const r of nomRows) {
        const key = r.rfc as string;
        const existing = map.get(key);
        if (existing) {
          existing.cantidad += (r.cantidad as number);
          existing.monto += toNumber(r.monto);
        } else {
          map.set(key, { rfc: key, nombre: r.nombre as string, cantidad: r.cantidad as number, monto: toNumber(r.monto) });
        }
      }
      return Array.from(map.values()).sort((a, b) => b.monto - a.monto);
    }
    const [{ rows: recCfdis }, { rows: nomCfdis }] = await Promise.all([
      pool.query(`
        SELECT id, uuid, tipo_comprobante as "tipoComprobante", fecha_emision as "fechaEmision",
          rfc_emisor as "rfcEmisor", nombre_emisor as "nombreEmisor",
          rfc_receptor as "rfcReceptor", nombre_receptor as "nombreReceptor",
          (${BASE_MONTO})::float as monto,
          metodo_pago as "metodoPago",
          regimen_fiscal_emisor as "regimenFiscalEmisor",
          regimen_fiscal_receptor as "regimenFiscalReceptor"
        FROM cfdis
        WHERE ${esReceptor} AND tipo_comprobante = 'I' AND metodo_pago IN ('PUE', 'PPD')
          AND (uso_cfdi != 'G01' OR uso_cfdi IS NULL)
          AND ${VIGENTE_ER} AND ${RANGO_FECHA}
          ${rfReceptor}
          AND rfc_emisor = $3
        ORDER BY fecha_emision DESC
      `, [fechaInicio, fechaFin, rfc]),
      pool.query(`
        SELECT id, uuid, tipo_comprobante as "tipoComprobante", fecha_emision as "fechaEmision",
          rfc_emisor as "rfcEmisor", nombre_emisor as "nombreEmisor",
          rfc_receptor as "rfcReceptor", nombre_receptor as "nombreReceptor",
          total_mxn::float as monto,
          metodo_pago as "metodoPago",
          regimen_fiscal_emisor as "regimenFiscalEmisor",
          regimen_fiscal_receptor as "regimenFiscalReceptor"
        FROM cfdis
        WHERE ${esEmisor} AND tipo_comprobante = 'N'
          AND ${VIGENTE_ER} AND ${RANGO_FECHA}
          ${rfEmisor}
          AND rfc_receptor = $3
        ORDER BY fecha_emision DESC
      `, [fechaInicio, fechaFin, rfc]),
    ]);
    const combined = [...recCfdis, ...nomCfdis].sort((a: any, b: any) =>
      new Date(b.fechaEmision).getTime() - new Date(a.fechaEmision).getTime()
    );
    return combined as DrillDownCfdiItem[];
  }

  throw new Error('Categoría de drill-down no válida');
}

// ─────────────────────────────────────────────────────────────────────────────
// Export Excel del Estado de Resultados
// ─────────────────────────────────────────────────────────────────────────────

export async function exportEstadoResultadosToExcel(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  _tenantId: string,
  contribuyenteId?: string | null,
  regimen?: string | null,
): Promise<Buffer> {
  const data = await getEstadoResultadosDetallado(pool, fechaInicio, fechaFin, _tenantId, contribuyenteId, regimen);

  const workbook = new ExcelJS.Workbook();
  const sheet = workbook.addWorksheet('Estado de Resultados');

  sheet.columns = [
    { header: 'Concepto', key: 'concepto', width: 35 },
    { header: 'Monto Actual', key: 'actual', width: 20 },
    { header: '% Vertical', key: 'vertical', width: 12 },
    { header: 'Año Anterior', key: 'anterior', width: 20 },
    { header: 'Var. %', key: 'variacion', width: 12 },
  ];

  // Header style
  sheet.getRow(1).font = { bold: true, color: { argb: 'FFFFFFFF' } };
  sheet.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF4472C4' } };

  const ventas = data.ventas || 1;

  const rows = [
    { concepto: 'Ventas', actual: data.ventas, vertical: (data.ventas / ventas) * 100, anterior: data.anterior.ventas, variacion: data.anterior.ventas ? ((data.ventas - data.anterior.ventas) / data.anterior.ventas) * 100 : 0 },
    { concepto: 'Devoluciones y cancelaciones', actual: -data.devoluciones, vertical: -(data.devoluciones / ventas) * 100, anterior: -data.anterior.devoluciones, variacion: data.anterior.devoluciones ? ((-data.devoluciones + data.anterior.devoluciones) / data.anterior.devoluciones) * 100 : 0 },
    { concepto: 'Ventas netas', actual: data.ventasNetas, vertical: (data.ventasNetas / ventas) * 100, anterior: data.anterior.ventasNetas, variacion: data.anterior.ventasNetas ? ((data.ventasNetas - data.anterior.ventasNetas) / data.anterior.ventasNetas) * 100 : 0, isTotal: true },
    { concepto: 'Costo de ventas', actual: -data.costoVentas, vertical: -(data.costoVentas / ventas) * 100, anterior: -data.anterior.costoVentas, variacion: data.anterior.costoVentas ? ((-data.costoVentas + data.anterior.costoVentas) / data.anterior.costoVentas) * 100 : 0 },
    { concepto: 'Utilidad bruta', actual: data.utilidadBruta, vertical: (data.utilidadBruta / ventas) * 100, anterior: data.anterior.utilidadBruta, variacion: data.anterior.utilidadBruta ? ((data.utilidadBruta - data.anterior.utilidadBruta) / data.anterior.utilidadBruta) * 100 : 0, isTotal: true },
    { concepto: 'Gastos operativos', actual: -data.gastosOperativos, vertical: -(data.gastosOperativos / ventas) * 100, anterior: -data.anterior.gastosOperativos, variacion: data.anterior.gastosOperativos ? ((-data.gastosOperativos + data.anterior.gastosOperativos) / data.anterior.gastosOperativos) * 100 : 0 },
    { concepto: 'Utilidad de la operación', actual: data.utilidadOperacion, vertical: (data.utilidadOperacion / ventas) * 100, anterior: data.anterior.utilidadOperacion, variacion: data.anterior.utilidadOperacion ? ((data.utilidadOperacion - data.anterior.utilidadOperacion) / data.anterior.utilidadOperacion) * 100 : 0, isTotal: true },
  ];

  rows.forEach((r) => {
    const row = sheet.addRow({
      concepto: r.concepto,
      actual: r.actual,
      vertical: `${r.vertical.toFixed(1)}%`,
      anterior: r.anterior,
      variacion: `${r.variacion.toFixed(1)}%`,
    });
    if (r.isTotal) {
      row.font = { bold: true };
    }
    // Color para montos negativos
    const actualCell = row.getCell(2);
    if (r.actual < 0) {
      actualCell.font = { ...(row.font || {}), color: { argb: 'FFC00000' } };
    } else if (r.actual > 0) {
      actualCell.font = { ...(row.font || {}), color: { argb: 'FF00B050' } };
    }
  });

  const buffer = await workbook.xlsx.writeBuffer();
  return Buffer.from(buffer);
}

export async function getCuentasXCobrar(
  pool: Pool,
  fechaInicio: string,
  fechaFin: string,
  regimen?: string,
  contribuyenteId?: string | null,
): Promise<CuentasPendientes> {
  const regimenFilter = regimen ? `AND regimen_fiscal_emisor = '${regimen}'` : '';
  const { esEmisor } = await resolveEmisorReceptor(pool, contribuyenteId);

  const { rows } = await pool.query(`
    SELECT
      rfc_receptor as rfc,
      nombre_receptor as nombre,
      COUNT(*)::int as cantidad,
      COALESCE(SUM(COALESCE(saldo_pendiente_mxn, total_mxn)), 0) as saldo
    FROM cfdis
    WHERE ${esEmisor} AND tipo_comprobante = 'I' AND metodo_pago = 'PPD'
      AND status NOT IN ('Cancelado', '0')
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') >= $1::date
      AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < ($2::date + interval '1 day')
      AND COALESCE(saldo_pendiente_mxn, total_mxn) > 0.01
      ${regimenFilter}
    GROUP BY rfc_receptor, nombre_receptor
    ORDER BY saldo DESC
  `, [fechaInicio, fechaFin]);

  const detalle = rows.map((r: any) => ({
    rfc: r.rfc,
    nombre: r.nombre,
    cantidad: r.cantidad,
    saldo: toNumber(r.saldo),
  }));

  return {
    cantidadCfdis: detalle.reduce((s, d) => s + d.cantidad, 0),
    saldoTotal: detalle.reduce((s, d) => s + d.saldo, 0),
    detalle,
  };
}
