"use strict";

const fs = require("node:fs");
const net = require("node:net");
const { execFile } = require("node:child_process");

const SOCKET_PATH = process.env.LAKE_LAMP_ACTION_SOCKET || "/run/guanghu/action-broker.sock";
const SSH_CONFIG = process.env.LAKE_LAMP_SSH_CONFIG || "/etc/guanghu/action-broker-ssh-config";

const REMOTE_COMMANDS = Object.freeze({
  "JD-FD-PRIMARY:inspect-services":
    "printf 'HOST='; hostname; printf 'SSH='; systemctl is-active ssh 2>/dev/null || systemctl is-active sshd 2>/dev/null; printf 'LIGHTHOUSE='; systemctl is-active guanghu-enterprise-lighthouse.service 2>/dev/null || true",
  "JD-FD-PRIMARY:health-check":
    "set -u; printf 'HOST='; hostname; printf 'HLCC='; systemctl is-active hlcc-jd-candidate.service 2>/dev/null || true; printf 'HLCC_HTTP='; curl -fsS --max-time 5 http://127.0.0.1:3340/api/healthz 2>/dev/null || printf 'unavailable\\n'; printf 'LIGHTHOUSE='; systemctl is-active guanghu-enterprise-lighthouse.service 2>/dev/null || true",
  "JD-FD-PRIMARY:inspect-code-channel-owner-auth":
    "set -eu; state=/var/lib/guanghu/personas/guanghu/hlcc-v16.0.1; db=\"$state/data/hlcc.db\"; config=\"$state/config/app.ini\"; printf 'HOST='; hostname; printf 'HLCC='; systemctl is-active hlcc-jd-candidate.service 2>/dev/null || true; printf 'DB_PRESENT='; test -f \"$db\" && printf 'yes\\n' || printf 'no\\n'; printf 'CONFIG_PRESENT='; test -f \"$config\" && printf 'yes\\n' || printf 'no\\n'; test -f \"$db\"; /usr/bin/sqlite3 -readonly -header -separator '|' \"$db\" \"select lower_name,is_active,is_admin,prohibit_login,login_type,passwd_hash_algo,length(passwd) as passwd_length,length(salt) as salt_length,updated_unix from user where lower_name='bingshuo';\"; /usr/bin/sqlite3 -readonly -header -separator '|' \"$db\" \"select lower_name,name,website,is_private,is_empty,default_branch,updated_unix from repository where lower_name in ('fifth-domain','guanghu-ice-heart') order by lower_name;\""
});

function remoteAction(command) {
  return () => run("/usr/bin/ssh", [
    "-F", SSH_CONFIG,
    "-o", "BatchMode=yes",
    "-o", "ConnectTimeout=10",
    "enterprise-lighthouse",
    command,
  ]);
}

const ACTIONS = Object.freeze({
  "JD-FD-PRIMARY:inspect-services": remoteAction(REMOTE_COMMANDS["JD-FD-PRIMARY:inspect-services"]),
  "JD-FD-PRIMARY:health-check": remoteAction(REMOTE_COMMANDS["JD-FD-PRIMARY:health-check"]),
  "JD-FD-PRIMARY:inspect-code-channel-owner-auth": remoteAction(REMOTE_COMMANDS["JD-FD-PRIMARY:inspect-code-channel-owner-auth"]),
});

function run(file, args) {
  return new Promise(resolve => execFile(file, args, { timeout: 30000, maxBuffer: 100000 }, (error, stdout, stderr) => resolve({
    ok: !error,
    exit_code: error ? (Number.isInteger(error.code) ? error.code : 1) : 0,
    stdout: String(stdout || "").slice(0, 100000),
    stderr: String(stderr || "").slice(0, 10000),
  })));
}

function reply(socket, value) { socket.end(`${JSON.stringify(value)}\n`); }

if (require.main === module) {
  fs.mkdirSync(require("node:path").dirname(SOCKET_PATH), { recursive: true, mode: 0o755 });
  try { fs.unlinkSync(SOCKET_PATH); } catch (error) { if (error.code !== "ENOENT") throw error; }
  const server = net.createServer({ allowHalfOpen: true }, socket => {
    let input = "";
    socket.setTimeout(5000, () => socket.destroy());
    socket.on("data", chunk => { input += chunk.toString("utf8"); if (input.length > 4096) socket.destroy(); });
    socket.on("end", async () => {
      let request;
      try { request = JSON.parse(input); } catch { return reply(socket, { ok: false, error: "invalid_request" }); }
      if (!request || request.cmd || request.command || request.shell || request.args) return reply(socket, { ok: false, error: "arbitrary_command_forbidden" });
      const action = ACTIONS[`${request.target}:${request.action}`];
      if (!action) return reply(socket, { ok: false, error: "action_not_registered" });
      reply(socket, await action());
    });
  });
  server.listen(SOCKET_PATH, () => {
    fs.chownSync(SOCKET_PATH, 0, Number(process.env.LAKE_LAMP_AUTHZ_GID || 0));
    fs.chmodSync(SOCKET_PATH, 0o660);
  });
}

module.exports = { ACTIONS, REMOTE_COMMANDS };
