import { readFileSync, readdirSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { normalizePath } from "vite";
import type { Plugin, ResolvedConfig } from "vite";

interface Options {
  sourceDir: string;
}

type JsonValue = string | number | boolean | null | JsonObject | JsonValue[];
type JsonObject = { [key: string]: JsonValue };

function deepSortKeys(obj: JsonObject): JsonObject {
  const sorted: JsonObject = {};
  for (const key of Object.keys(obj).sort()) {
    const value = obj[key];
    if (value !== null && typeof value === "object" && !Array.isArray(value)) {
      sorted[key] = deepSortKeys(value as JsonObject);
    } else {
      sorted[key] = value;
    }
  }
  return sorted;
}

function sortFile(filePath: string): void {
  const raw = readFileSync(filePath, "utf-8");
  const parsed = JSON.parse(raw) as JsonObject;
  const sorted = deepSortKeys(parsed);
  const output = JSON.stringify(sorted, null, "\t") + "\n";

  if (raw !== output) {
    writeFileSync(filePath, output, "utf-8");
  }
}

function sortAllFiles(sourceDir: string): void {
  const files = readdirSync(sourceDir).filter((f) => f.endsWith(".json"));
  for (const file of files) {
    sortFile(join(sourceDir, file));
  }
}

export function i18nextSortPlugin(options: Options): Plugin {
  let resolvedSourceDir: string;

  return {
    name: "i18next-sort",

    configResolved(config: ResolvedConfig) {
      resolvedSourceDir = normalizePath(resolve(config.root, options.sourceDir));
    },

    buildStart() {
      sortAllFiles(resolvedSourceDir);
    },

    configureServer(server) {
      server.watcher.add(resolvedSourceDir);

      server.watcher.on("change", (file: string) => {
        if (file.startsWith(resolvedSourceDir) && file.endsWith(".json")) {
          sortFile(file);
        }
      });
    },
  };
}
