import http from "node:http";
import os from "node:os";
import { loadConfig } from "./config.js";
import { getToken, readJson, requirePost, sendJson } from "./http.js";
import { getLanUrls } from "./network.js";
import { getDesktopAdapter } from "./platform/index.js";

const host = process.env.HER_AGENT_HOST || "127.0.0.1";
const port = Number(process.env.HER_AGENT_PORT || 8787);
const config = loadConfig();
const adapter = getDesktopAdapter();
const version = "0.1.1";
const build = "main-process-screen-and-input";

function assertAuthorized(req) {
  if (getToken(req) !== config.token) {
    const error = new Error("Unauthorized. Pass the token as Authorization: Bearer <token>.");
    error.statusCode = 401;
    throw error;
  }
}

async function handleControl(req, res, pathname) {
  requirePost(req);
  assertAuthorized(req);

  if (pathname === "/api/screenshot") {
    const body = await readJson(req);
    sendJson(res, 200, await adapter.screenshot(body));
    return;
  }

  const body = await readJson(req);
  console.log(`[${new Date().toISOString()}] ${pathname} ${JSON.stringify(body)}`);

  if (pathname === "/api/open-app") {
    sendJson(res, 200, await adapter.openApp(body));
    return;
  }

  if (pathname === "/api/notify") {
    sendJson(res, 200, await adapter.notify(body));
    return;
  }

  if (pathname === "/api/computer-action") {
    sendJson(res, 200, await adapter.computerAction(body));
    return;
  }

  if (pathname === "/api/run") {
    sendJson(res, 200, await adapter.runCommand(body));
    return;
  }

  if (pathname === "/api/terminal-run") {
    sendJson(res, 200, await adapter.terminalRun(body));
    return;
  }

  sendJson(res, 404, { ok: false, error: "Not found." });
}

async function handleScreenshotJpeg(req, res, url) {
  assertAuthorized(req);
  const started = Date.now();
  const width = clampNumber(url.searchParams.get("width"), 960, 480, 1920);
  const quality = clampNumber(url.searchParams.get("quality"), 62, 25, 90);
  const fast = url.searchParams.get("fast") === "1";
  const capture = await adapter.screenshotBuffer({
    format: "jpeg",
    width,
    quality,
    fast,
  });
  const elapsed = Date.now() - started;
  console.log(`[${new Date().toISOString()}] /api/screenshot.jpg ${elapsed}ms bytes=${capture.bytes.length} width=${width} quality=${quality} fast=${fast}`);
  res.writeHead(200, {
    "Content-Type": "image/jpeg",
    "Content-Length": capture.bytes.length,
    "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
    "Pragma": "no-cache",
    "Connection": "keep-alive",
    "X-Accel-Buffering": "no",
    "Access-Control-Allow-Origin": "*",
    "X-Her-Screenshot-Ms": String(elapsed),
  });
  res.end(capture.bytes);
}

function clampNumber(value, fallback, min, max) {
  const number = Number(value || fallback);
  if (!Number.isFinite(number)) return fallback;
  return Math.max(min, Math.min(max, Math.round(number)));
}

const server = http.createServer(async (req, res) => {
  try {
    if (req.method === "OPTIONS") {
      sendJson(res, 204, {});
      return;
    }

    const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);

    if (req.method === "GET" && url.pathname === "/api/screenshot.jpg") {
      await handleScreenshotJpeg(req, res, url);
      return;
    }

    if (req.method === "GET" && url.pathname === "/health") {
      sendJson(res, 200, {
        ok: true,
        name: "Her Desktop Agent",
        deviceName: os.hostname(),
        version,
        build,
        bind: `http://${host}:${port}`,
        lanUrls: getLanUrls(port),
        adapter: adapter.getAdapterInfo(),
      });
      return;
    }

    if (req.method === "GET" && url.pathname === "/api/status") {
      assertAuthorized(req);
      sendJson(res, 200, {
        ok: true,
        deviceName: os.hostname(),
        version,
        build,
        lanUrls: getLanUrls(port),
        directUrls: getLanUrls(port),
      });
      return;
    }

    await handleControl(req, res, url.pathname);
  } catch (error) {
    sendJson(res, error.statusCode || 500, {
      ok: false,
      error: error.message || "Unknown error.",
      stdout: error.stdout,
      stderr: error.stderr,
      allowed: error.allowed,
    });
  }
});

server.on("upgrade", (req, socket) => {
  socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
  socket.destroy();
});

server.listen(port, host, () => {
  const lanUrls = getLanUrls(port);

  console.log("Her Desktop Agent is running.");
  console.log(`Local: http://${host}:${port}`);
  if (lanUrls.length > 0) {
    console.log("LAN:");
    for (const url of lanUrls) console.log(`  ${url}`);
  }
  console.log(`Token: ${config.token}`);
  console.log(`Terminal: ${process.env.HER_AGENT_ENABLE_TERMINAL === "1" ? "enabled" : "disabled"}`);
  console.log(`Config: ${config.configPath}`);
  console.log("");
  console.log("For phone testing on the same Wi-Fi, restart with:");
  console.log("  HER_AGENT_HOST=0.0.0.0 npm start");
});
