import type express from "express";

import { resolveBrowserExecutableForPlatform } from "../chrome.executables.js";
import { createBrowserProfilesService } from "../profiles-service.js";
import type { BrowserRouteContext } from "../server-context.js";
import type { BrowserRouteRegistrar } from "./types.js";
import { getProfileContext, jsonError, toStringOrEmpty } from "./utils.js";

export function registerBrowserBasicRoutes(app: BrowserRouteRegistrar, ctx: BrowserRouteContext) {
  // Adapter to allow Express-typed handlers when underlying might be browser dispatcher
  const registrar = {
    get: (path: string, handler: (req: express.Request, res: express.Response) => any) => app.get(path, handler as any),
    post: (path: string, handler: (req: express.Request, res: express.Response) => any) => app.post(path, handler as any),
    delete: (path: string, handler: (req: express.Request, res: express.Response) => any) => app.delete(path, handler as any),
  };
  // List all profiles with their status
  registrar.get("/profiles", async (_req, res) => {
    try {
      const service = createBrowserProfilesService(ctx);
      const profiles = await service.listProfiles();
      res.json({ profiles });
    } catch (err) {
      jsonError(res, 500, String(err));
    }
  });

  // Get status (profile-aware)
  registrar.get("/", async (req, res) => {
    let current: ReturnType<typeof ctx.state>;
    try {
      current = ctx.state();
    } catch {
      return jsonError(res, 503, "browser server not started");
    }

    const profileCtx = getProfileContext(req, ctx);
    if ("error" in profileCtx) {
      return jsonError(res, profileCtx.status, profileCtx.error);
    }

    const [cdpHttp, cdpReady] = await Promise.all([
      profileCtx.isHttpReachable(300),
      profileCtx.isReachable(600),
    ]);

    const profileState = current.profiles.get(profileCtx.profile.name);
    let detectedBrowser: string | null = null;
    let detectedExecutablePath: string | null = null;
    let detectError: string | null = null;

    try {
      const detected = resolveBrowserExecutableForPlatform(current.resolved, process.platform);
      if (detected) {
        detectedBrowser = detected.kind;
        detectedExecutablePath = detected.path;
      }
    } catch (err) {
      detectError = String(err);
    }

    res.json({
      enabled: current.resolved.enabled,
      controlUrl: current.resolved.controlUrl,
      profile: profileCtx.profile.name,
      running: cdpReady,
      cdpReady,
      cdpHttp,
      pid: profileState?.running?.pid ?? null,
      cdpPort: profileCtx.profile.cdpPort,
      cdpUrl: profileCtx.profile.cdpUrl,
      chosenBrowser: profileState?.running?.exe.kind ?? null,
      detectedBrowser,
      detectedExecutablePath,
      detectError,
      userDataDir: profileState?.running?.userDataDir ?? null,
      color: profileCtx.profile.color,
      headless: current.resolved.headless,
      noSandbox: current.resolved.noSandbox,
      executablePath: current.resolved.executablePath ?? null,
      attachOnly: current.resolved.attachOnly,
    });
  });

  // Start browser (profile-aware)
  registrar.post("/start", async (req, res) => {
    const profileCtx = getProfileContext(req, ctx);
    if ("error" in profileCtx) {
      return jsonError(res, profileCtx.status, profileCtx.error);
    }

    try {
      await profileCtx.ensureBrowserAvailable();
      res.json({ ok: true, profile: profileCtx.profile.name });
    } catch (err) {
      jsonError(res, 500, String(err));
    }
  });

  // Stop browser (profile-aware)
  registrar.post("/stop", async (req, res) => {
    const profileCtx = getProfileContext(req, ctx);
    if ("error" in profileCtx) {
      return jsonError(res, profileCtx.status, profileCtx.error);
    }

    try {
      const result = await profileCtx.stopRunningBrowser();
      res.json({
        ok: true,
        stopped: result.stopped,
        profile: profileCtx.profile.name,
      });
    } catch (err) {
      jsonError(res, 500, String(err));
    }
  });

  // Reset profile (profile-aware)
  registrar.post("/reset-profile", async (req, res) => {
    const profileCtx = getProfileContext(req, ctx);
    if ("error" in profileCtx) {
      return jsonError(res, profileCtx.status, profileCtx.error);
    }

    try {
      const result = await profileCtx.resetProfile();
      res.json({ ok: true, profile: profileCtx.profile.name, ...result });
    } catch (err) {
      jsonError(res, 500, String(err));
    }
  });

  // Create a new profile
  registrar.post("/profiles/create", async (req, res) => {
    const name = toStringOrEmpty((req.body as { name?: unknown })?.name);
    const color = toStringOrEmpty((req.body as { color?: unknown })?.color);
    const cdpUrl = toStringOrEmpty((req.body as { cdpUrl?: unknown })?.cdpUrl);
    const driver = toStringOrEmpty((req.body as { driver?: unknown })?.driver) as
      | "clawd"
      | "extension"
      | "";

    if (!name) return jsonError(res, 400, "name is required");

    try {
      const service = createBrowserProfilesService(ctx);
      const result = await service.createProfile({
        name,
        color: color || undefined,
        cdpUrl: cdpUrl || undefined,
        driver: driver === "extension" ? "extension" : undefined,
      });
      res.json(result);
    } catch (err) {
      const msg = String(err);
      if (msg.includes("already exists")) {
        return jsonError(res, 409, msg);
      }
      if (msg.includes("invalid profile name")) {
        return jsonError(res, 400, msg);
      }
      if (msg.includes("no available CDP ports")) {
        return jsonError(res, 507, msg);
      }
      if (msg.includes("cdpUrl")) {
        return jsonError(res, 400, msg);
      }
      jsonError(res, 500, msg);
    }
  });

  // Delete a profile
  registrar.delete("/profiles/:name", async (req, res) => {
    const name = toStringOrEmpty(req.params.name);
    if (!name) return jsonError(res, 400, "profile name is required");

    try {
      const service = createBrowserProfilesService(ctx);
      const result = await service.deleteProfile(name);
      res.json(result);
    } catch (err) {
      const msg = String(err);
      if (msg.includes("invalid profile name")) {
        return jsonError(res, 400, msg);
      }
      if (msg.includes("default profile")) {
        return jsonError(res, 400, msg);
      }
      if (msg.includes("not found")) {
        return jsonError(res, 404, msg);
      }
      jsonError(res, 500, msg);
    }
  });
}
