import fs from "fs";
import path from "path";
import { createRequire } from "module";
import { fileURLToPath } from "url";

const require = createRequire(import.meta.url);
const Ajv = require("ajv");

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "..");
const contentRoot = path.join(repoRoot, "content");
const schemaRoot = path.join(contentRoot, "schema");

const ajv = new Ajv({
  allErrors: true,
  schemaId: "auto",
  jsonPointers: true,
});

function normalizePath(filePath) {
  return filePath.split(path.sep).join("/");
}

function readJson(filePath) {
  return JSON.parse(fs.readFileSync(filePath, "utf8"));
}

function listFilesRecursive(dirPath) {
  const entries = fs.readdirSync(dirPath, { withFileTypes: true });
  const files = [];
  for (const entry of entries) {
    const fullPath = path.join(dirPath, entry.name);
    if (entry.isDirectory()) {
      files.push(...listFilesRecursive(fullPath));
    } else {
      files.push(fullPath);
    }
  }
  return files;
}

const jobs = [
  {
    schema: "abilities.schema.json",
    files: [path.join(contentRoot, "abilities.json")],
  },
  {
    schema: "dialogues.schema.json",
    files: [path.join(contentRoot, "dialogues.json")],
  },
  {
    schema: "factions.schema.json",
    files: [path.join(contentRoot, "factions.json")],
  },
  {
    schema: "images.schema.json",
    files: [path.join(contentRoot, "images.json")],
  },
  {
    schema: "items.schema.json",
    files: [path.join(contentRoot, "items.json")],
  },
  {
    schema: "loot_tables.schema.json",
    files: [path.join(contentRoot, "loot_tables.json")],
  },
  {
    schema: "monsters.schema.json",
    files: [path.join(contentRoot, "monsters.json")],
  },
  {
    schema: "npc_templates.schema.json",
    files: [path.join(contentRoot, "npc_templates.json")],
  },
  {
    schema: "quests.schema.json",
    files: [path.join(contentRoot, "quests.json")],
  },
  {
    schema: "worlds.schema.json",
    files: [path.join(contentRoot, "worlds.json")],
  },
  {
    schema: "world.schema.json",
    files: listFilesRecursive(path.join(contentRoot, "worlds")).filter((filePath) => path.basename(filePath) === "world.json"),
  },
  {
    schema: "world-bookmarks.schema.json",
    files: listFilesRecursive(path.join(contentRoot, "worlds")).filter((filePath) => path.basename(filePath) === "bookmarks.json"),
  },
  {
    schema: "world-chunk.schema.json",
    files: listFilesRecursive(path.join(contentRoot, "worlds")).filter((filePath) => /^-?\d+_-?\d+\.json$/i.test(path.basename(filePath))),
  },
  {
    schema: "dev_config.schema.json",
    files: [path.join(contentRoot, "dev_config.json")],
  },
  {
    schema: "npcs.schema.json",
    files: fs.existsSync(path.join(contentRoot, "npcs.json")) ? [path.join(contentRoot, "npcs.json")] : [],
  },
];

let hasErrors = false;
let validatedCount = 0;

for (const job of jobs) {
  const schemaPath = path.join(schemaRoot, job.schema);
  const schema = readJson(schemaPath);
  let validate;
  try {
    validate = ajv.compile(schema);
  } catch (error) {
    hasErrors = true;
    console.error(`Schema compile failed: ${normalizePath(path.relative(repoRoot, schemaPath))}`);
    console.error(String(error));
    continue;
  }

  for (const filePath of job.files) {
    const payload = readJson(filePath);
    const valid = validate(payload);
    validatedCount += 1;
    if (!valid) {
      hasErrors = true;
      console.error(`Validation failed: ${normalizePath(path.relative(repoRoot, filePath))}`);
      for (const error of validate.errors || []) {
        const instancePath = error.dataPath || "/";
        console.error(`  ${instancePath} ${error.message}`);
      }
    }
  }
}

if (hasErrors) {
  process.exitCode = 1;
} else {
  console.log(`Validated ${validatedCount} content file(s) successfully.`);
}
