import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { dirname, join } from "node:path";
import { spawnSync } from "node:child_process";

const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;

interface UpdateCache {
  checkedAt: number;
  latest: string;
}

export function currentCliVersion(): string {
  try {
    return JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf8")).version;
  } catch {
    return "0.0.0";
  }
}

export function compareVersions(a: string, b: string): number {
  const left = a.split("-")[0]!.split(".").map(Number);
  const right = b.split("-")[0]!.split(".").map(Number);
  for (let i = 0; i < 3; i++) {
    const difference = (left[i] || 0) - (right[i] || 0);
    if (difference) return difference > 0 ? 1 : -1;
  }
  return 0;
}

function cachePath(): string {
  return process.env.WRNEXUS_UPDATE_CACHE ?? join(homedir(), ".wrnexus", "update-check.json");
}

function cachedLatest(now: number): string | null {
  try {
    const cached = JSON.parse(readFileSync(cachePath(), "utf8")) as UpdateCache;
    return now - cached.checkedAt < CHECK_INTERVAL_MS ? cached.latest : null;
  } catch {
    return null;
  }
}

function registryLatest(): string | null {
  const npm = process.platform === "win32" ? "npm.cmd" : "npm";
  const result = spawnSync(npm, ["view", "@wrnexus/cli", "version"], {
    encoding: "utf8",
    timeout: 5000,
    windowsHide: true,
  });
  const version = (result.stdout ?? "").trim();
  return result.status === 0 && /^\d+\.\d+\.\d+/.test(version) ? version : null;
}

/** Check at most once per day and print a non-blocking upgrade suggestion. */
export function notifyIfUpdateAvailable(current: string, command?: string): void {
  if (
    process.env.WRNEXUS_NO_UPDATE_CHECK === "1" ||
    command === "update" ||
    command === "upgrade"
  ) {
    return;
  }
  const now = Date.now();
  let latest = cachedLatest(now);
  if (!latest) {
    latest = registryLatest();
    if (!latest) return;
    try {
      const file = cachePath();
      if (!existsSync(dirname(file))) mkdirSync(dirname(file), { recursive: true });
      writeFileSync(file, JSON.stringify({ checkedAt: now, latest }) + "\n", "utf8");
    } catch {
      // A read-only home directory must never break the CLI.
    }
  }
  if (compareVersions(latest, current) > 0) {
    console.log(
      `\n  Update available: WRNexusJS ${current} → ${latest}\n` +
        `  Run: wrnexus update --latest\n`,
    );
  }
}
