import { readdirSync, readFileSync, statSync } from 'fs';
import { join } from 'path';

/**
 * Criterio del spec: toda consulta del vertical filtra por empresa_id.
 *
 * Test de forma (como crm-multitenancy.spec.ts): recorre los servicios y exige que
 * cada findMany / findFirst / count / updateMany / deleteMany sobre tablas inm_
 * lleve `empresa_id` en su argumento, o filtre por el padre (`operacion_id`,
 * `plan_id`, `proyecto_id`) de un registro que ya se validó contra la empresa.
 * Las excepciones son las tareas diarias, que recorren todas las empresas a propósito.
 */
const DIR = __dirname;

function servicios(dir: string): string[] {
  return readdirSync(dir).flatMap((n) => {
    const p = join(dir, n);
    if (statSync(p).isDirectory()) return servicios(p);
    return n.endsWith('.service.ts') ? [p] : [];
  });
}

/** Devuelve el texto del argumento de cada llamada `.inm_x.metodo(`, balanceando llaves. */
function llamadas(fuente: string) {
  const re = /\.(inm_\w+)\.(findMany|findFirst|count|updateMany|deleteMany)\(/g;
  const out: Array<{ tabla: string; metodo: string; arg: string; linea: number }> = [];
  let m: RegExpExecArray | null;
  while ((m = re.exec(fuente))) {
    let i = re.lastIndex;
    let prof = 1;
    while (i < fuente.length && prof > 0) {
      if (fuente[i] === '(') prof++;
      else if (fuente[i] === ')') prof--;
      i++;
    }
    out.push({
      tabla: m[1],
      metodo: m[2],
      arg: fuente.slice(re.lastIndex, i - 1),
      linea: fuente.slice(0, m.index).split('\n').length,
    });
  }
  return out;
}

const PERMITIDAS: Array<{ archivo: string; tabla: string; metodo: string }> = [
  // Job diario: vence las cotizaciones de todas las empresas.
  { archivo: 'cotizaciones.service.ts', tabla: 'inm_cotizaciones', metodo: 'updateMany' },
  // Job diario: recorre los parámetros de cada empresa que usa el módulo.
  { archivo: 'cartera.service.ts', tabla: 'inm_parametros', metodo: 'findMany' },
  // Tarea mensual: recorre los proyectos en fideicomiso de todas las empresas.
  { archivo: 'fideicomiso.service.ts', tabla: 'inm_proyectos', metodo: 'findMany' },
];

const FILTROS_PADRE = /empresa_id|operacion_id|plan_id|cobro_id/;

describe('inmobiliario — multiempresa', () => {
  const archivos = servicios(DIR);

  it('hay servicios que revisar', () => {
    expect(archivos.length).toBeGreaterThan(8);
  });

  it('cada consulta de lectura o masiva filtra por la empresa (o por un padre ya validado)', () => {
    const sinFiltro: string[] = [];
    for (const archivo of archivos) {
      const nombre = archivo.split('/').pop() ?? archivo;
      for (const c of llamadas(readFileSync(archivo, 'utf8'))) {
        if (PERMITIDAS.some((p) => p.archivo === nombre && p.tabla === c.tabla && p.metodo === c.metodo)) continue;
        if (!FILTROS_PADRE.test(c.arg)) sinFiltro.push(`${nombre}:${c.linea} ${c.tabla}.${c.metodo}`);
      }
    }
    expect(sinFiltro).toEqual([]);
  });
});
