import crypto from "node:crypto";
import path from "node:path";
import type { BrowserRouteContext } from "../server-context.js";
import {
  readBody,
  resolveTargetIdFromBody,
  resolveTargetIdFromQuery,
  withPlaywrightRouteContext,
} from "./agent.shared.js";
import { resolveWritableOutputPathOrRespond } from "./output-paths.js";
import { DEFAULT_TRACE_DIR } from "./path-output.js";
import type { BrowserRouteRegistrar } from "./types.js";
import { toBoolean, toStringOrEmpty } from "./utils.js";

export function registerBrowserAgentDebugRoutes(
  app: BrowserRouteRegistrar,
  ctx: BrowserRouteContext,
) {
  app.get("/console", async (req, res) => {
    const targetId = resolveTargetIdFromQuery(req.query);
    const level = typeof req.query.level === "string" ? req.query.level : "";

    await withPlaywrightRouteContext({
      req,
      res,
      ctx,
      targetId,
      feature: "console messages",
      run: async ({ cdpUrl, tab, pw }) => {
        const messages = await pw.getConsoleMessagesViaPlaywright({
          cdpUrl,
          targetId: tab.targetId,
          level: level.trim() || undefined,
        });
        res.json({ ok: true, messages, targetId: tab.targetId });
      },
    });
  });

  app.get("/errors", async (req, res) => {
    const targetId = resolveTargetIdFromQuery(req.query);
    const clear = toBoolean(req.query.clear) ?? false;

    await withPlaywrightRouteContext({
      req,
      res,
      ctx,
      targetId,
      feature: "page errors",
      run: async ({ cdpUrl, tab, pw }) => {
        const result = await pw.getPageErrorsViaPlaywright({
          cdpUrl,
          targetId: tab.targetId,
          clear,
        });
        res.json({ ok: true, targetId: tab.targetId, ...result });
      },
    });
  });

  app.get("/requests", async (req, res) => {
    const targetId = resolveTargetIdFromQuery(req.query);
    const filter = typeof req.query.filter === "string" ? req.query.filter : "";
    const clear = toBoolean(req.query.clear) ?? false;

    await withPlaywrightRouteContext({
      req,
      res,
      ctx,
      targetId,
      feature: "network requests",
      run: async ({ cdpUrl, tab, pw }) => {
        const result = await pw.getNetworkRequestsViaPlaywright({
          cdpUrl,
          targetId: tab.targetId,
          filter: filter.trim() || undefined,
          clear,
        });
        res.json({ ok: true, targetId: tab.targetId, ...result });
      },
    });
  });

  app.post("/trace/start", async (req, res) => {
    const body = readBody(req);
    const targetId = resolveTargetIdFromBody(body);
    const screenshots = toBoolean(body.screenshots) ?? undefined;
    const snapshots = toBoolean(body.snapshots) ?? undefined;
    const sources = toBoolean(body.sources) ?? undefined;

    await withPlaywrightRouteContext({
      req,
      res,
      ctx,
      targetId,
      feature: "trace start",
      run: async ({ cdpUrl, tab, pw }) => {
        await pw.traceStartViaPlaywright({
          cdpUrl,
          targetId: tab.targetId,
          screenshots,
          snapshots,
          sources,
        });
        res.json({ ok: true, targetId: tab.targetId });
      },
    });
  });

  app.post("/trace/stop", async (req, res) => {
    const body = readBody(req);
    const targetId = resolveTargetIdFromBody(body);
    const out = toStringOrEmpty(body.path) || "";

    await withPlaywrightRouteContext({
      req,
      res,
      ctx,
      targetId,
      feature: "trace stop",
      run: async ({ cdpUrl, tab, pw }) => {
        const id = crypto.randomUUID();
        const tracePath = await resolveWritableOutputPathOrRespond({
          res,
          rootDir: DEFAULT_TRACE_DIR,
          requestedPath: out,
          scopeLabel: "trace directory",
          defaultFileName: `browser-trace-${id}.zip`,
          ensureRootDir: true,
        });
        if (!tracePath) {
          return;
        }
        await pw.traceStopViaPlaywright({
          cdpUrl,
          targetId: tab.targetId,
          path: tracePath,
        });
        res.json({
          ok: true,
          targetId: tab.targetId,
          path: path.resolve(tracePath),
        });
      },
    });
  });
}
