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

function singleLine(value, maxLength = 255) {
  return String(value ?? "")
    .replace(/[\r\n\0]/g, "")
    .trim()
    .slice(0, maxLength);
}

function validateNativeRdpOptions(options) {
  const host = singleLine(options?.host);
  const port = Number(options?.port ?? 3389);
  if (!host || host.length > 253 || /[\\/]/.test(host)) {
    throw new Error("Invalid RDP host");
  }
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new Error("Invalid RDP port");
  }
  return {
    host,
    port,
    username: singleLine(options?.username),
    domain: singleLine(options?.domain),
  };
}

function buildRdpFile(options) {
  const { host, port, username, domain } = validateNativeRdpOptions(options);
  const address = host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`;
  const qualifiedUsername = username
    ? domain
      ? `${domain}\\${username}`
      : username
    : "";
  return [
    `full address:s:${address}`,
    "prompt for credentials:i:1",
    "administrative session:i:0",
    ...(qualifiedUsername ? [`username:s:${qualifiedUsername}`] : []),
    "",
  ].join("\r\n");
}

async function launchNativeRdp(options, platform = process.platform) {
  if (platform !== "win32") {
    return {
      success: false,
      error: "Windows Remote Desktop is only available on Windows",
    };
  }

  const rdpContent = buildRdpFile(options);
  const tempDir = await fs.promises.mkdtemp(
    path.join(os.tmpdir(), "termix-rdp-"),
  );
  const rdpPath = path.join(tempDir, "connection.rdp");
  await fs.promises.writeFile(rdpPath, rdpContent, {
    encoding: "utf8",
    mode: 0o600,
  });

  return new Promise((resolve) => {
    const child = spawn("mstsc.exe", [rdpPath], {
      detached: true,
      windowsHide: true,
      stdio: "ignore",
    });
    const cleanup = () =>
      fs.promises.rm(tempDir, { recursive: true, force: true }).catch(() => {});
    child.once("error", (error) => {
      cleanup();
      resolve({ success: false, error: error.message });
    });
    child.once("spawn", () => {
      child.unref();
      setTimeout(cleanup, 30_000).unref();
      resolve({ success: true });
    });
  });
}

module.exports = { buildRdpFile, launchNativeRdp, validateNativeRdpOptions };
