import { INestApplication } from "@nestjs/common";
import {
  DiscoveredRoute,
  PUBLIC_ROUTES,
  bootTestApp,
  concretePath,
  httpRequest,
  isPublicRoute,
} from "./e2e-helpers";

// RENOMBRADO a proposito (era "tenant-context-required"): esta prueba mide
// COBERTURA DEL GUARD DE AUTENTICACION, no aislamiento entre tenants. Hoy no
// existe ningun concepto de tenant en el JWT ni en el request — lo unico que
// esto verifica es que JwtAuthGuard este puesto en cada ruta no-publica. Va
// a seguir en verde durante TODA la conversion de los 12 modulos, sin
// importar cuantos falten: no mide progreso de la migracion multi-tenant.
//
// Sirve para otra cosa, real y permanente: detectar un controlador NUEVO que
// alguien agregue sin @UseGuards — ese es el bug que esta prueba de verdad
// atrapa.
//
// La prueba que SI mide aislamiento (token valido, tenant no resoluble) esta
// en tenant-isolation-required.e2e-spec.ts — esa es la que hay que ver subir
// a verde a medida que se convierte cada modulo.
describe("Cobertura del guard de autenticacion (e2e)", () => {
  let app: INestApplication;
  let port: number;
  let routes: DiscoveredRoute[];

  beforeAll(async () => {
    const booted = await bootTestApp();
    app = booted.app;
    port = booted.port;
    routes = booted.routes;
  }, 60000);

  afterAll(async () => {
    await app?.close();
  });

  it("descubrio rutas reales (si esto da 0, algo cambio en como Nest monta las rutas)", () => {
    expect(routes.length).toBeGreaterThan(20);
  });

  it("cada ruta publica declarada en PUBLIC_ROUTES existe realmente en la app", () => {
    for (const publicRoute of PUBLIC_ROUTES) {
      const exists = routes.some(
        (r) => r.method === publicRoute.method && r.path === publicRoute.path,
      );
      expect({ publicRoute, exists }).toEqual({ publicRoute, exists: true });
    }
  });

  it("ninguna ruta no-publica responde 2xx sin Authorization (JwtAuthGuard esta puesto)", async () => {
    const failures: Array<{ method: string; path: string; status: number }> =
      [];
    const statusCounts: Record<number, number> = {};
    let checked = 0;

    for (const route of routes) {
      if (isPublicRoute(route.method, route.path)) continue;
      checked++;

      const { status } = await httpRequest(
        port,
        route.method,
        concretePath(route.path),
      );
      statusCounts[status] = (statusCounts[status] || 0) + 1;

      if (status >= 200 && status < 300) {
        failures.push({ ...route, status });
      }
    }

    // eslint-disable-next-line no-console
    console.log(
      `[auth-guard-coverage] ${checked} ruta(s) no-publicas verificadas, ${failures.length} respondieron 2xx sin auth. Distribucion de status: ${JSON.stringify(statusCounts)}`,
    );

    // Chequeo cruzado: si la ruta de descubrimiento estuviera mal (bug real
    // que encontre armando esta prueba: doble-prefijo por setGlobalPrefix),
    // TODO daria 404 — no porque el guard rechace, sino porque la URL no
    // existe. Practicamente todo tiene que ser 401 (JwtAuthGuard), no 404.
    const total = Object.values(statusCounts).reduce((a, b) => a + b, 0);
    const only401 = statusCounts[401] || 0;
    expect(only401 / total).toBeGreaterThan(0.9);

    expect(failures).toEqual([]);
  }, 60000);

  it("regla 7(a) a nivel de rutas REGISTRADAS: ninguna ruta de switch de tenant existe todavia", () => {
    const switchLike = routes.filter((r) => /switch/i.test(r.path));
    expect(switchLike).toEqual([]);
  });
});
