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

export interface ContribuyenteContext {
  contribuyenteId: string | null;
  rfc: string;
  rfcLength: number;
  /**
   * DEPRECATED — filtro genérico `AND (contribuyente_id = X OR rfc_emisor=X_RFC OR rfc_receptor=X_RFC)`.
   * Útil solo cuando el query no distingue lado (emisor vs receptor).
   * Para queries con semantic por lado, usa `esEmisor` / `esReceptor`.
   */
  contribFilter: string;
  /**
   * Fragmento SQL que identifica al contribuyente como **emisor** del CFDI.
   * Reemplaza al par `type = 'EMITIDO' AND contribuyente_id = X`. Usa RFC
   * como fuente de verdad (el `type` y `contribuyente_id` en BD pueden ser
   * inconsistentes cuando dos contribuyentes del mismo tenant se facturan
   * entre sí — el RFC en la posición emisor/receptor no tiene ambigüedad).
   * Sin el `AND` prefijo — úsalo dentro de expresión compuesta.
   */
  esEmisor: string;
  /** Similar a `esEmisor`, identifica al contribuyente como **receptor**. */
  esReceptor: string;
}

/**
 * Resolves the RFC and builds a CFDI contribuyente filter fragment.
 * - If contribuyenteId is provided: RFC comes from contribuyentes table (tenant BD),
 *   filter restricts CFDIs to that contribuyente_id.
 * - If not: RFC comes from Tenant (central BD), no contribuyente filter (Horux360 compat).
 */
export async function resolveContribuyenteContext(
  pool: Pool,
  tenantId: string,
  contribuyenteId?: string | null,
): Promise<ContribuyenteContext> {
  if (contribuyenteId) {
    // Sanitize: UUIDs are only hex + hyphens
    const safeId = contribuyenteId.replace(/[^a-f0-9-]/gi, '');
    const { rows } = await pool.query(
      'SELECT rfc FROM contribuyentes WHERE entidad_id = $1',
      [safeId],
    );
    const rfc: string = rows[0]?.rfc || '';
    const safeRfc = rfc.replace(/[^A-Z0-9]/gi, '').toUpperCase();

    // Filtro genérico (deprecated): contribuyente_id directo O RFC en
    // cualquier lado. Sigue disponible para queries legacy que no distinguen
    // lado. Los callers modernos deberían usar esEmisor/esReceptor.
    let contribFilter = '';
    if (safeId && safeRfc) {
      contribFilter = `AND (contribuyente_id = '${safeId}' OR UPPER(rfc_emisor) = '${safeRfc}' OR UPPER(rfc_receptor) = '${safeRfc}')`;
    } else if (safeId) {
      contribFilter = `AND contribuyente_id = '${safeId}'`;
    }

    // esEmisor / esReceptor: fuente de verdad por posición del RFC.
    // Reemplazan al par `type = 'EMITIDO/RECIBIDO' AND contribuyente_id = X`.
    const esEmisor = safeRfc ? `UPPER(rfc_emisor) = '${safeRfc}'` : `1=0`;
    const esReceptor = safeRfc ? `UPPER(rfc_receptor) = '${safeRfc}'` : `1=0`;

    return {
      contribuyenteId: safeId,
      rfc,
      rfcLength: rfc.length,
      contribFilter,
      esEmisor,
      esReceptor,
    };
  }

  // Horux360 mode: no contribuyente → RFC from central BD
  const tenant = await prisma.tenant.findUnique({
    where: { id: tenantId },
    select: { rfc: true },
  });
  const rfc = tenant?.rfc || '';
  const safeRfc = rfc.replace(/[^A-Z0-9]/gi, '').toUpperCase();
  // Para Horux 360 single-tenant, el RFC del tenant actúa como el contrib.
  const esEmisor = safeRfc ? `UPPER(rfc_emisor) = '${safeRfc}'` : `type = 'EMITIDO'`;
  const esReceptor = safeRfc ? `UPPER(rfc_receptor) = '${safeRfc}'` : `type = 'RECIBIDO'`;
  return {
    contribuyenteId: null,
    rfc,
    rfcLength: rfc.length,
    contribFilter: '',
    esEmisor,
    esReceptor,
  };
}
