/**
 * Linux systemd installer for Siraya Printer Service.
 * Run as root: node installer/linux/install-service.js
 */
const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");

const EXIT_OK = 0;
const EXIT_ERR = 1;

if (process.platform !== "linux") {
  console.error("This installer is for Linux only.");
  process.exit(EXIT_ERR);
}

const innoInstall = process.env.SIRAYA_INNO_INSTALL === "1";
const installDir =
  process.env.SIRAYA_INSTALL_DIR || "/opt/siraya/printer";
const dataDir =
  process.env.SIRAYA_DATA_DIR || "/var/lib/siraya/printer";
const serviceUser = process.env.SIRAYA_SERVICE_USER || "siraya-printer";
const serviceName = "siraya-printer";
const bundledNode =
  process.env.SIRAYA_NODE_EXE ||
  path.join(installDir, "runtime", "node");
const appRoot = innoInstall
  ? path.resolve(installDir)
  : path.resolve(__dirname, "..", "..");

function run(cmd) {
  execSync(cmd, { stdio: "inherit" });
}

function runQuiet(cmd) {
  try {
    execSync(cmd, { stdio: "ignore" });
  } catch {
    /* ignore */
  }
}

function copyRecursive(src, dest) {
  if (!fs.existsSync(src)) return;
  fs.mkdirSync(dest, { recursive: true });
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
    const s = path.join(src, entry.name);
    const d = path.join(dest, entry.name);
    if (entry.isDirectory()) copyRecursive(s, d);
    else fs.copyFileSync(s, d);
  }
}

function ensureServiceUser() {
  try {
    execSync(`id ${serviceUser}`, { stdio: "ignore" });
  } catch {
    run(
      `useradd --system --no-create-home --shell /usr/sbin/nologin ${serviceUser}`,
    );
  }
}

function ensureEnvFile() {
  fs.mkdirSync(path.join(dataDir, "queue"), { recursive: true });
  fs.mkdirSync(path.join(dataDir, "logs"), { recursive: true });
  const envFile = path.join(dataDir, ".env");
  const envExample = path.join(installDir, ".env.example");
  if (!fs.existsSync(envFile) && fs.existsSync(envExample)) {
    let env = fs.readFileSync(envExample, "utf8");
    env += `\nPRINT_DATA_DIR=${dataDir}/queue\n`;
    env += `SIRAYA_DATA_DIR=${dataDir}\n`;
    fs.writeFileSync(envFile, env);
  }
  run(`chown -R ${serviceUser}:${serviceUser} ${dataDir}`);
}

function copyAppFiles() {
  const exclude = new Set(["node_modules", ".git", "installer", "test", "dist"]);
  fs.mkdirSync(installDir, { recursive: true });
  for (const name of fs.readdirSync(appRoot)) {
    if (exclude.has(name)) continue;
    const src = path.join(appRoot, name);
    const dest = path.join(installDir, name);
    const stat = fs.statSync(src);
    if (stat.isDirectory()) copyRecursive(src, dest);
    else fs.copyFileSync(src, dest);
  }
  if (fs.existsSync(path.join(appRoot, "node_modules"))) {
    copyRecursive(
      path.join(appRoot, "node_modules"),
      path.join(installDir, "node_modules"),
    );
  } else {
    execSync("npm ci --omit=dev", { cwd: installDir, stdio: "inherit" });
  }
}

function writeSystemdUnit() {
  const nodeExe = fs.existsSync(bundledNode) ? bundledNode : process.execPath;
  const unit = `[Unit]
Description=Siraya POS thermal receipt print agent
After=network.target cups.service

[Service]
Type=simple
User=${serviceUser}
Group=${serviceUser}
WorkingDirectory=${installDir}
Environment=NODE_ENV=production
Environment=SIRAYA_DATA_DIR=${dataDir}
Environment=DOTENV_CONFIG_PATH=${dataDir}/.env
Environment=HOST=127.0.0.1
Environment=PORT=5000
ExecStart=${nodeExe} ${path.join(installDir, "index.js")}
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
`;
  const unitPath = `/etc/systemd/system/${serviceName}.service`;
  fs.writeFileSync(unitPath, unit);
  console.log("Wrote", unitPath);
}

function installSystemd() {
  writeSystemdUnit();
  run("systemctl daemon-reload");
  run(`systemctl enable ${serviceName}.service`);
  runQuiet(`systemctl stop ${serviceName}.service`);
  run(`systemctl start ${serviceName}.service`);
  run(`chown -R ${serviceUser}:${serviceUser} ${installDir}`);
}

function main() {
  if (process.getuid && process.getuid() !== 0) {
    console.error("Run as root: sudo node installer/linux/install-service.js");
    process.exit(EXIT_ERR);
  }

  console.log("Siraya Printer Service (Linux)");
  console.log("  install dir:", installDir);
  console.log("  data dir:  ", dataDir);

  if (innoInstall && !fs.existsSync(path.join(installDir, "index.js"))) {
    console.error("Expected app at", installDir);
    process.exit(EXIT_ERR);
  }

  if (!innoInstall) {
    copyAppFiles();
  }

  ensureServiceUser();
  ensureEnvFile();
  installSystemd();
  console.log("Service started:", serviceName);
  process.exit(EXIT_OK);
}

main();
