/**
 * Helpers para construir fragmentos AND adicionales en WHERE clauses según
 * los toggles "Considerar activos" y "Considerar NCs" de la UI de impuestos.
 *
 * - considerarActivos === false → excluir facturas relacionadas a activos:
 *   1) I directo con uso_cfdi I01-I08.
 *   2) P pagando una I-activo (vía uuid_relacionado).
 *   3) E que referencia una I-activo o una P-de-activo (vía cfdis_relacionados,
 *      cualquier tipoRel — cubre NCs tipoRel=01, devoluciones tipoRel=03, etc.).
 * - considerarNCs === false → excluir facturas tipo E con cfdi_tipo_relacion = '01'.
 *
 * Cuando ambos son true (default backend = "include todo"), retorna string
 * vacío. Esto preserva el comportamiento histórico para callers que no pasan
 * los flags (ej. dashboard, reportes).
 *
 * Las versiones `Alias` se usan en subqueries con alias de tabla
 * (ej. `cfdis e` en SUM_E_REFERENCING_*). El filtro de NCs aplica directo;
 * el de activos aplica también pero algunos predicados son no-op funcional
 * en subqueries que filtran por tipo_comprobante específico (Postgres los
 * optimiza away).
 */

const ACTIVOS_USOS = "('I01','I02','I03','I04','I05','I06','I07','I08')";

/**
 * Predicado SQL que detecta si el row actual (sin alias de tabla, asume
 * `FROM cfdis`) referencia un activo directamente (I), indirectamente vía
 * pago (P→I), o transitivamente vía relación (E→I, E→P→I).
 *
 * IMPORTANTE — qualifying outer refs: dentro de los subqueries `cfdis i_act`
 * y `cfdis r_act`, la tabla interna también tiene columnas `uuid_relacionado`
 * y `cfdis_relacionados`. Una referencia no-qualificada las resolvería a las
 * columnas internas (NO al row outer), volviendo el predicado a no-op.
 * Por eso usamos `cfdis.uuid_relacionado` y `cfdis.cfdis_relacionados`
 * explícitamente — fuerza la resolución al outer.
 */
function activosExclusionNoAlias(): string {
  return `
    AND NOT (tipo_comprobante = 'I' AND uso_cfdi IN ${ACTIVOS_USOS})
    AND NOT (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_USOS}
    ))
    AND NOT (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_USOS})
          OR (r_act.tipo_comprobante = 'P' AND EXISTS (
            SELECT 1 FROM cfdis pi_act
            WHERE LOWER(pi_act.uuid) = LOWER(r_act.uuid_relacionado)
              AND pi_act.tipo_comprobante = 'I'
              AND pi_act.uso_cfdi IN ${ACTIVOS_USOS}
          ))
        )
    ))
  `.trim();
}

/**
 * Misma lógica que activosExclusionNoAlias pero referenciando columnas con
 * el alias de tabla externo (ej. 'e' en `FROM cfdis e`).
 */
function activosExclusionAlias(alias: string): string {
  return `
    AND NOT (${alias}.tipo_comprobante = 'I' AND ${alias}.uso_cfdi IN ${ACTIVOS_USOS})
    AND NOT (${alias}.tipo_comprobante = 'P' AND EXISTS (
      SELECT 1 FROM cfdis i_act
      WHERE LOWER(i_act.uuid) = LOWER(${alias}.uuid_relacionado)
        AND i_act.tipo_comprobante = 'I'
        AND i_act.uso_cfdi IN ${ACTIVOS_USOS}
    ))
    AND NOT (${alias}.tipo_comprobante = 'E' AND ${alias}.cfdis_relacionados IS NOT NULL AND EXISTS (
      SELECT 1 FROM cfdis r_act
      WHERE LOWER(r_act.uuid) = ANY(string_to_array(LOWER(${alias}.cfdis_relacionados), '|'))
        AND (
          (r_act.tipo_comprobante = 'I' AND r_act.uso_cfdi IN ${ACTIVOS_USOS})
          OR (r_act.tipo_comprobante = 'P' AND EXISTS (
            SELECT 1 FROM cfdis pi_act
            WHERE LOWER(pi_act.uuid) = LOWER(r_act.uuid_relacionado)
              AND pi_act.tipo_comprobante = 'I'
              AND pi_act.uso_cfdi IN ${ACTIVOS_USOS}
          ))
        )
    ))
  `.trim();
}

export function buildExtraFilters(
  considerarActivos: boolean,
  considerarNCs: boolean,
): string {
  const parts: string[] = [];
  if (!considerarActivos) {
    parts.push(activosExclusionNoAlias());
  }
  if (!considerarNCs) {
    parts.push(`AND NOT (tipo_comprobante = 'E' AND COALESCE(cfdi_tipo_relacion, '') = '01')`);
  }
  return parts.length > 0 ? ' ' + parts.join(' ') : '';
}

export function buildExtraFiltersAlias(
  alias: string,
  considerarActivos: boolean,
  considerarNCs: boolean,
): string {
  const parts: string[] = [];
  if (!considerarActivos) {
    parts.push(activosExclusionAlias(alias));
  }
  if (!considerarNCs) {
    parts.push(`AND NOT (${alias}.tipo_comprobante = 'E' AND COALESCE(${alias}.cfdi_tipo_relacion, '') = '01')`);
  }
  return parts.length > 0 ? ' ' + parts.join(' ') : '';
}
