import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const SUPPORTED_LOCALES = [
  "en",
  "es",
  "de",
  "ja",
  "fr",
  "pt",
  "ru",
  "it",
  "nl",
  "pl",
  "zh",
  "hi",
  "ar",
  "bn",
  "id",
  "tr",
];

const TARGETS = [
  {
    name: "bot",
    directory: "apps/bot/locales",
  },
  {
    name: "web",
    directory: "apps/web/locales",
  },
];

const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(SCRIPT_DIR, "..", "..");
const CHECK_ONLY = process.argv.includes("--check");

const isObject = (value) => {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
};

const readJsonFile = (filePath) => {
  const raw = readFileSync(filePath, "utf-8");
  return JSON.parse(raw);
};

const writeJsonFile = (filePath, content) => {
  writeFileSync(filePath, `${JSON.stringify(content, null, 2)}\n`, "utf-8");
};

const shapeFromBase = (base, override) => {
  if (Array.isArray(base)) {
    return Array.isArray(override) ? override : base;
  }

  if (isObject(base)) {
    const result = {};
    const overrideObject = isObject(override) ? override : {};

    for (const [key, value] of Object.entries(base)) {
      result[key] = shapeFromBase(value, overrideObject[key]);
    }

    return result;
  }

  return typeof override === typeof base ? override : base;
};

const collectLeafPaths = (input, prefix = "", output = []) => {
  if (isObject(input)) {
    for (const [key, value] of Object.entries(input)) {
      const nextPrefix = prefix.length > 0 ? `${prefix}.${key}` : key;
      collectLeafPaths(value, nextPrefix, output);
    }
    return output;
  }

  output.push(prefix);
  return output;
};

let hasError = false;

for (const target of TARGETS) {
  const targetDirectory = path.resolve(REPO_ROOT, target.directory);
  const defaultLocalePath = path.join(targetDirectory, "en.json");

  if (!existsSync(defaultLocalePath)) {
    console.error(
      `[i18n:${target.name}] missing default locale file: ${defaultLocalePath}`,
    );
    hasError = true;
    continue;
  }

  mkdirSync(targetDirectory, { recursive: true });

  const baseDictionary = readJsonFile(defaultLocalePath);
  const baseLeafPaths = new Set(collectLeafPaths(baseDictionary));

  for (const locale of SUPPORTED_LOCALES) {
    const localePath = path.join(targetDirectory, `${locale}.json`);
    const localeExists = existsSync(localePath);
    const currentDictionary = localeExists ? readJsonFile(localePath) : {};
    const normalizedDictionary = shapeFromBase(
      baseDictionary,
      currentDictionary,
    );

    const normalizedText = JSON.stringify(normalizedDictionary, null, 2);
    const currentText = JSON.stringify(currentDictionary, null, 2);

    if (!CHECK_ONLY && (!localeExists || normalizedText !== currentText)) {
      writeJsonFile(localePath, normalizedDictionary);
      console.log(`[i18n:${target.name}] synced ${locale}.json`);
    }

    if (CHECK_ONLY) {
      const localeLeafPaths = new Set(collectLeafPaths(currentDictionary));

      const missingPaths = [...baseLeafPaths].filter(
        (key) => !localeLeafPaths.has(key),
      );
      const extraPaths = [...localeLeafPaths].filter(
        (key) => !baseLeafPaths.has(key),
      );

      if (missingPaths.length > 0 || extraPaths.length > 0) {
        hasError = true;
        console.error(`[i18n:${target.name}] ${locale}.json is out of sync`);

        if (missingPaths.length > 0) {
          console.error(`  missing keys: ${missingPaths.join(", ")}`);
        }

        if (extraPaths.length > 0) {
          console.error(`  extra keys: ${extraPaths.join(", ")}`);
        }
      }
    }
  }
}

if (CHECK_ONLY && hasError) {
  process.exitCode = 1;
}
