import * as fs from "fs";
import * as path from "path";

// Guardia permanente contra un incidente que ya paso una vez en este mismo
// trabajo: el glob del CLI (src/config/typeorm.config.ts,
// migrations: [..., "migrations", "*{.ts,.js}"]) carga TODO archivo .ts/.js
// que este directamente en src/migrations/ como si fuera una migracion — sin
// filtrar por contenido. Un archivo que no sea una migracion real ahi rompe
// el CLI en tiempo de EJECUCION, no de build (paso con
// schema-divergence.spec.ts antes de moverlo a verification/, que el glob de
// un solo nivel no alcanza). Ese fix fue reactivo; esta prueba es preventiva
// — barato de mantener, y evita toda una familia de fallas futuras,
// especialmente relevante para cuando el runner del panel corra migraciones
// programaticamente en vez de por el CLI manual.
const migrationsDir = path.join(__dirname, "..");

function listGlobMatchedFiles(): string[] {
  // Mismo alcance que el glob real: NO entra a subcarpetas (fs.readdirSync
  // sin recursion — por eso verification/ mismo, un nivel mas adentro, no
  // cuenta), coincide con .ts o .js directamente en migrationsDir.
  return fs
    .readdirSync(migrationsDir, { withFileTypes: true })
    .filter(
      (entry) => entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js")),
    )
    .map((entry) => entry.name);
}

describe("todo archivo que el glob de migraciones del CLI cargaria es una migracion real", () => {
  it("cada archivo exporta al menos una clase con up() y down() (MigrationInterface)", () => {
    const files = listGlobMatchedFiles();
    expect(files.length).toBeGreaterThan(0);

    const problems: string[] = [];

    for (const file of files) {
      const modulePath = path.join(migrationsDir, file);
      let mod: unknown;
      try {
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        mod = require(modulePath);
      } catch (e) {
        problems.push(`${file}: no se pudo cargar (${(e as Error).message})`);
        continue;
      }

      const exportedClasses = Object.values(mod as Record<string, unknown>).filter(
        (v): v is { prototype: Record<string, unknown> } =>
          typeof v === "function" && !!(v as { prototype?: unknown }).prototype,
      );

      const implementsMigrationInterface = exportedClasses.some(
        (cls) =>
          typeof cls.prototype.up === "function" && typeof cls.prototype.down === "function",
      );

      if (!implementsMigrationInterface) {
        problems.push(
          `${file}: no exporta ninguna clase con up() y down() — el glob del CLI lo cargaria ` +
            "como migracion pero no implementa MigrationInterface. Si no es una migracion real, " +
            "sacarlo de src/migrations/ (ej. a verification/, que el glob no alcanza).",
        );
      }
    }

    if (problems.length > 0) {
      throw new Error(
        `${problems.length} archivo(s) que el glob de migraciones cargaria no son una migracion valida:\n\n` +
          problems.join("\n"),
      );
    }
  });
});
