export const runtime = "nodejs";

import fs from "fs";
import path from "path";
import { z } from "zod";
import { NextResponse } from "next/server";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { resolveApiKey } from "@/shared/services/apiKeyResolver";
import { resolveMitmDataDir } from "@/mitm/dataDir";
import { KIRO_MITM_PROFILE } from "@/mitm/targets/kiro";
import { ANTIGRAVITY_MITM_PROFILE } from "@/mitm/targets/antigravity";

type MitmTargetRoute = {
  id: string;
  name: string;
  targetHost: string;
  targetPort: number;
  localPort: number;
  endpoints: string[];
  enabled: boolean;
};

type MitmStats = {
  startedAt: string | null;
  totalRequests: number;
  interceptedRequests: number;
  activeConnections: number;
  lastRequestAt: string | null;
  lastInterceptAt: string | null;
};

type MitmConfig = {
  port: number;
  targets: MitmTargetRoute[];
};

const DEFAULT_PORT = 443;
const MITM_PORT_ERROR =
  "Transparent MITM interception currently requires port 443 because DNS override does not redirect destination ports.";

const updateMitmSchema = z.object({
  enabled: z.boolean().optional(),
  apiKey: z.string().optional(),
  keyId: z.string().optional(),
  sudoPassword: z.string().optional(),
  port: z.coerce.number().int().min(1).max(65535).optional(),
});

const regenerateSchema = z.object({
  action: z.literal("regenerate-cert").optional(),
});

function getMitmDir() {
  return path.join(resolveMitmDataDir(), "mitm");
}

function getConfigPath() {
  return path.join(getMitmDir(), "settings.json");
}

function getStatsPath() {
  return path.join(getMitmDir(), "stats.json");
}

function getCertPath() {
  return path.join(getMitmDir(), "server.crt");
}

function getKeyPath() {
  return path.join(getMitmDir(), "server.key");
}

function defaultTargets(port = DEFAULT_PORT): MitmTargetRoute[] {
  const allHosts = [
    ANTIGRAVITY_MITM_PROFILE.targetHost,
    ...(ANTIGRAVITY_MITM_PROFILE.additionalHosts || []),
  ];
  return [
    {
      id: ANTIGRAVITY_MITM_PROFILE.id,
      name: ANTIGRAVITY_MITM_PROFILE.name,
      targetHost: allHosts.join(", "),
      targetPort: ANTIGRAVITY_MITM_PROFILE.targetPort,
      localPort: port,
      endpoints: ANTIGRAVITY_MITM_PROFILE.apiEndpoints,
      enabled: true,
    },
    {
      id: KIRO_MITM_PROFILE.id,
      name: KIRO_MITM_PROFILE.name,
      targetHost: KIRO_MITM_PROFILE.targetHost,
      targetPort: KIRO_MITM_PROFILE.targetPort,
      localPort: KIRO_MITM_PROFILE.localPort,
      endpoints: KIRO_MITM_PROFILE.apiEndpoints,
      enabled: false,
    },
  ];
}

function readConfig(): MitmConfig {
  try {
    JSON.parse(fs.readFileSync(getConfigPath(), "utf8"));
    return {
      port: DEFAULT_PORT,
      targets: defaultTargets(DEFAULT_PORT),
    };
  } catch {
    return {
      port: DEFAULT_PORT,
      targets: defaultTargets(DEFAULT_PORT),
    };
  }
}

function writeConfig() {
  const mitmDir = getMitmDir();
  fs.mkdirSync(mitmDir, { recursive: true });
  fs.writeFileSync(getConfigPath(), JSON.stringify({ port: DEFAULT_PORT }, null, 2));
}

function readStats(): MitmStats {
  try {
    const raw = JSON.parse(fs.readFileSync(getStatsPath(), "utf8"));
    return {
      startedAt: typeof raw.startedAt === "string" ? raw.startedAt : null,
      totalRequests: Number(raw.totalRequests || 0),
      interceptedRequests: Number(raw.interceptedRequests || 0),
      activeConnections: Number(raw.activeConnections || 0),
      lastRequestAt: typeof raw.lastRequestAt === "string" ? raw.lastRequestAt : null,
      lastInterceptAt: typeof raw.lastInterceptAt === "string" ? raw.lastInterceptAt : null,
    };
  } catch {
    return {
      startedAt: null,
      totalRequests: 0,
      interceptedRequests: 0,
      activeConnections: 0,
      lastRequestAt: null,
      lastInterceptAt: null,
    };
  }
}

async function buildMitmResponse() {
  const { getMitmStatus, getCachedPassword } = await import("@/mitm/manager.runtime");
  const status = await getMitmStatus();
  const config = readConfig();
  const stats = readStats();

  return {
    running: status.running,
    pid: status.pid || null,
    dnsConfigured: status.dnsConfigured || false,
    certExists: status.certExists || fs.existsSync(getCertPath()),
    hasCachedPassword: !!getCachedPassword(),
    port: config.port,
    targets: config.targets,
    stats,
  };
}

export async function GET(request: Request) {
  const authError = await requireManagementAuth(request);
  if (authError) return authError;

  try {
    const { searchParams } = new URL(request.url);
    if (searchParams.get("download") === "cert") {
      const certPath = getCertPath();
      if (!fs.existsSync(certPath)) {
        return NextResponse.json({ error: "MITM certificate not found" }, { status: 404 });
      }
      return new NextResponse(fs.readFileSync(certPath), {
        headers: {
          "Content-Type": "application/x-pem-file",
          "Content-Disposition": 'attachment; filename="omniroute-mitm-ca.crt"',
        },
      });
    }

    return NextResponse.json(await buildMitmResponse());
  } catch (error) {
    const message = error instanceof Error ? error.message : "Failed to load MITM settings";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}

export async function PUT(request: Request) {
  const authError = await requireManagementAuth(request);
  if (authError) return authError;

  try {
    const rawBody = await request.json().catch(() => ({}));
    const parsed = updateMitmSchema.safeParse(rawBody);
    if (!parsed.success) {
      return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
    }

    const config = readConfig();
    if (parsed.data.port !== undefined && parsed.data.port !== DEFAULT_PORT) {
      return NextResponse.json({ error: MITM_PORT_ERROR }, { status: 400 });
    }

    if (parsed.data.port !== undefined) {
      config.port = DEFAULT_PORT;
      config.targets = defaultTargets(config.port);
      writeConfig();
    }

    if (typeof parsed.data.enabled === "boolean") {
      const { getCachedPassword, setCachedPassword, startMitm, stopMitm } =
        await import("@/mitm/manager.runtime");
      const { isRoot } = await import("@/mitm/systemCommands");
      const isWin = process.platform === "win32";
      const isRootUser = !isWin && isRoot();
      const sudoPassword = parsed.data.sudoPassword || getCachedPassword() || "";

      if (parsed.data.enabled) {
        const apiKey = await resolveApiKey(parsed.data.keyId || null, parsed.data.apiKey || null);
        if (!apiKey || (!isWin && !isRootUser && !sudoPassword)) {
          return NextResponse.json(
            { error: isWin ? "Missing apiKey" : "Missing apiKey or sudoPassword" },
            { status: 400 }
          );
        }
        await startMitm(apiKey, sudoPassword, { port: config.port });
        if (!isWin) setCachedPassword(sudoPassword);
      } else {
        if (!isWin && !isRootUser && !sudoPassword) {
          return NextResponse.json({ error: "Missing sudoPassword" }, { status: 400 });
        }
        await stopMitm(sudoPassword);
        if (!isWin && parsed.data.sudoPassword) setCachedPassword(parsed.data.sudoPassword);
      }
    }

    return NextResponse.json(await buildMitmResponse());
  } catch (error) {
    const message = error instanceof Error ? error.message : "Failed to update MITM settings";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}

export async function POST(request: Request) {
  const authError = await requireManagementAuth(request);
  if (authError) return authError;

  try {
    const rawBody = await request.json().catch(() => ({}));
    const parsed = regenerateSchema.safeParse(rawBody);
    if (!parsed.success) {
      return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
    }

    const { getMitmStatus } = await import("@/mitm/manager.runtime");
    const status = await getMitmStatus();
    if (status.running) {
      return NextResponse.json(
        { error: "Stop the MITM proxy before regenerating certificates" },
        { status: 409 }
      );
    }

    for (const filePath of [getCertPath(), getKeyPath()]) {
      try {
        if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
      } catch {
        /* ignore */
      }
    }

    const { generateCert } = await import("@/mitm/cert/generate");
    await generateCert();

    return NextResponse.json(await buildMitmResponse());
  } catch (error) {
    const message =
      error instanceof Error ? error.message : "Failed to regenerate MITM certificate";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
