const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");

const SERVICE_NAME = "SirayaPrinterService";

const SKIP_SNAPSHOT = new Set(["versions", "daemon", "node_modules"]);

function getInstallRoot() {
  if (process.platform !== "win32") return null;
  return path.join(
    process.env.ProgramFiles || "C:\\Program Files",
    "Siraya",
    "Printer",
  );
}

function getVersionsDir() {
  const root = getInstallRoot();
  return root ? path.join(root, "versions") : null;
}

function copyRecursive(src, dest, skipNames = SKIP_SNAPSHOT) {
  fs.mkdirSync(dest, { recursive: true });
  for (const name of fs.readdirSync(src)) {
    if (skipNames.has(name)) continue;
    const s = path.join(src, name);
    const d = path.join(dest, name);
    const st = fs.statSync(s);
    if (st.isDirectory()) copyRecursive(s, d, skipNames);
    else fs.copyFileSync(s, d);
  }
}

function listInstalledVersions() {
  const dir = getVersionsDir();
  if (!dir || !fs.existsSync(dir)) return [];
  return fs
    .readdirSync(dir)
    .filter((n) => fs.statSync(path.join(dir, n)).isDirectory())
    .sort();
}

function getCurrentVersionPointer() {
  const root = getInstallRoot();
  if (!root) return null;
  const ptr = path.join(root, "current-version.txt");
  if (!fs.existsSync(ptr)) return null;
  return fs.readFileSync(ptr, "utf8").trim();
}

function setCurrentVersion(version) {
  const root = getInstallRoot();
  if (!root) throw new Error("NOT_WINDOWS");
  fs.writeFileSync(path.join(root, "current-version.txt"), version, "utf8");
}

function getInstalledVersionFromPackage() {
  const root = getInstallRoot();
  if (!root) return null;
  try {
    const pkg = JSON.parse(
      fs.readFileSync(path.join(root, "package.json"), "utf8"),
    );
    return pkg.version || null;
  } catch {
    return null;
  }
}

function snapshotCurrentVersion(version) {
  const root = getInstallRoot();
  const versionsDir = getVersionsDir();
  if (!root || !versionsDir) throw new Error("NOT_WINDOWS");
  const label = version || getCurrentVersionPointer() || getInstalledVersionFromPackage() || "unknown";
  const dest = path.join(versionsDir, label);
  if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });
  copyRecursive(root, dest);
  return dest;
}

function restoreSnapshot(version) {
  const root = getInstallRoot();
  const versionsDir = getVersionsDir();
  if (!root || !versionsDir) throw new Error("NOT_WINDOWS");
  const src = path.join(versionsDir, version);
  if (!fs.existsSync(src)) throw new Error(`SNAPSHOT_NOT_FOUND:${version}`);

  for (const name of fs.readdirSync(root)) {
    if (name === "versions") continue;
    const p = path.join(root, name);
    fs.rmSync(p, { recursive: true, force: true });
  }
  copyRecursive(src, root, new Set(["versions"]));
  setCurrentVersion(version);
  return version;
}

function rollbackToPrevious() {
  const versions = listInstalledVersions().sort();
  const current = getCurrentVersionPointer();
  const idx = versions.indexOf(current);
  if (idx <= 0) throw new Error("NO_PREVIOUS_VERSION");
  const prev = versions[idx - 1];
  restoreSnapshot(prev);
  try {
    execSync(`net stop ${SERVICE_NAME}`, { stdio: "ignore" });
  } catch {
    /* ignore */
  }
  execSync(`net start ${SERVICE_NAME}`, { stdio: "ignore" });
  return prev;
}

module.exports = {
  listInstalledVersions,
  getCurrentVersionPointer,
  setCurrentVersion,
  getInstalledVersionFromPackage,
  snapshotCurrentVersion,
  restoreSnapshot,
  rollbackToPrevious,
};
