import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { basename, join, resolve } from "node:path";
import {
  CURRENT_COMPATIBILITY_DATE,
  CURRENT_FRAMEWORK_BEHAVIOUR,
  loadRawConfig,
  resolveCompatibility,
} from "@wrnexus/styles";

const CONFIG_NAMES = ["wrnexus.config.ts", "wrnexus.config.js", "wrnexus.config.mjs"];

function configPath(root: string): string | undefined {
  return CONFIG_NAMES.map((name) => join(root, name)).find(existsSync);
}

export async function compatibilityReport(appRoot: string) {
  return resolveCompatibility(await loadRawConfig(resolve(appRoot)));
}

export function upgradeCompatibility(appRoot: string): {
  file: string;
  backup: string;
  changed: boolean;
} {
  const root = resolve(appRoot);
  const file = configPath(root);
  if (!file) throw new Error("WRN-COMPATIBILITY-NO-CONFIG: wrnexus.config.ts was not found.");
  const source = readFileSync(file, "utf8");
  let updated = source;
  const replace = (name: string, value: string) => {
    const pattern = new RegExp(`(^\\s*${name}\\s*:\\s*)(?:["'][^"']*["']|\\d+)(\\s*,?)`, "m");
    if (pattern.test(updated)) updated = updated.replace(pattern, `$1${value}$2`);
    else {
      const object = /(?:const\s+config[^=]*=|defineConfig\s*\(|export\s+default)\s*\{/m;
      if (!object.test(updated))
        throw new Error("WRN-COMPATIBILITY-CONFIG-SHAPE: unable to locate the root config object.");
      updated = updated.replace(object, (match) => `${match}\n  ${name}: ${value},`);
    }
  };
  replace("compatibilityDate", JSON.stringify(CURRENT_COMPATIBILITY_DATE));
  replace("frameworkBehaviour", String(CURRENT_FRAMEWORK_BEHAVIOUR));
  if (updated === source) return { file, backup: "", changed: false };
  const directory = join(root, ".wrnexus", "compatibility-backups");
  mkdirSync(directory, { recursive: true });
  const backup = join(directory, `${Date.now()}-${basename(file)}`);
  copyFileSync(file, backup);
  writeFileSync(file, updated, "utf8");
  return { file, backup, changed: true };
}

export async function runCompatibilityCommand(
  appRoot: string,
  command = "check",
  args: string[] = [],
): Promise<boolean> {
  if (command === "upgrade") {
    const result = upgradeCompatibility(appRoot);
    if (args.includes("--json")) console.log(JSON.stringify(result, null, 2));
    else
      console.log(
        result.changed
          ? `✓ Compatibility policy upgraded\n  backup: ${result.backup}`
          : "✓ Compatibility policy already current",
      );
  }
  const report = await compatibilityReport(appRoot);
  if (args.includes("--json")) console.log(JSON.stringify(report, null, 2));
  else {
    console.log(`Compatibility date: ${report.effectiveDate} (current ${report.currentDate})`);
    console.log(
      `Framework behaviour: ${report.effectiveBehaviour} (current ${report.currentBehaviour})`,
    );
    for (const message of report.messages) console.log(`- ${message}`);
  }
  return !report.needsUpgrade && !report.future;
}
