import {
  getProxyConfig,
  setProxyConfig,
  getProxyForLevel,
  deleteProxyForLevel,
  resolveProxyForConnection,
} from "../../../../lib/localDb";
import { clearDispatcherCache } from "@omniroute/open-sse/utils/proxyDispatcher";

const BASE_SUPPORTED_PROXY_TYPES = new Set(["http", "https"]);

function isSocks5Enabled() {
  return process.env.ENABLE_SOCKS5_PROXY === "true";
}

function getSupportedProxyTypes() {
  if (isSocks5Enabled()) {
    return new Set([...BASE_SUPPORTED_PROXY_TYPES, "socks5"]);
  }
  return BASE_SUPPORTED_PROXY_TYPES;
}

function supportedTypesMessage() {
  return isSocks5Enabled() ? "http, https, or socks5" : "http or https";
}

function createInvalidProxyError(message: string) {
  const error: any = new Error(message);
  error.status = 400;
  error.type = "invalid_request";
  return error;
}

function normalizeAndValidateProxy(proxy, pathLabel) {
  if (proxy === null || proxy === undefined) return proxy;
  if (typeof proxy !== "object" || Array.isArray(proxy)) {
    throw createInvalidProxyError(`${pathLabel} must be an object`);
  }

  const type = String(proxy.type || "http").toLowerCase();
  if (type === "socks5" && !isSocks5Enabled()) {
    throw createInvalidProxyError(
      "SOCKS5 proxy is disabled (set ENABLE_SOCKS5_PROXY=true to enable)"
    );
  }
  if (type.startsWith("socks") && type !== "socks5") {
    throw createInvalidProxyError(`${pathLabel}.type must be ${supportedTypesMessage()}`);
  }
  if (!getSupportedProxyTypes().has(type)) {
    throw createInvalidProxyError(`${pathLabel}.type must be ${supportedTypesMessage()}`);
  }

  return { ...proxy, type };
}

function normalizeAndValidateProxyMap(proxyMap, mapName) {
  if (proxyMap === undefined) return undefined;
  if (proxyMap === null || typeof proxyMap !== "object" || Array.isArray(proxyMap)) {
    throw createInvalidProxyError(`${mapName} must be an object`);
  }

  const normalizedMap = { ...proxyMap };
  for (const [id, proxy] of Object.entries(proxyMap)) {
    normalizedMap[id] = normalizeAndValidateProxy(proxy, `${mapName}.${id}`);
  }
  return normalizedMap;
}

function normalizeProxyPayload(body) {
  if (!body || typeof body !== "object" || Array.isArray(body)) {
    throw createInvalidProxyError("Request body must be an object");
  }

  const normalized = { ...body };
  if (Object.prototype.hasOwnProperty.call(body, "proxy")) {
    normalized.proxy = normalizeAndValidateProxy(body.proxy, "proxy");
  }
  if (Object.prototype.hasOwnProperty.call(body, "global")) {
    normalized.global = normalizeAndValidateProxy(body.global, "global");
  }
  for (const key of ["providers", "combos", "keys"]) {
    if (Object.prototype.hasOwnProperty.call(body, key)) {
      normalized[key] = normalizeAndValidateProxyMap(body[key], key);
    }
  }
  return normalized;
}

/**
 * GET /api/settings/proxy — get proxy configuration
 * Optional query params: ?level=global|provider|combo|key&id=xxx
 * Or: ?resolve=connectionId to resolve effective proxy
 */
export async function GET(request) {
  try {
    const { searchParams } = new URL(request.url);
    const level = searchParams.get("level");
    const id = searchParams.get("id");
    const resolveId = searchParams.get("resolve");

    // Resolve effective proxy for a connection
    if (resolveId) {
      const result = await resolveProxyForConnection(resolveId);
      return Response.json(result);
    }

    // Get proxy for a specific level
    if (level) {
      const proxy = await getProxyForLevel(level, id);
      return Response.json({ level, id, proxy });
    }

    // Get full config
    const config = await getProxyConfig();
    return Response.json(config);
  } catch (error) {
    return Response.json(
      { error: { message: error.message, type: "server_error" } },
      { status: 500 }
    );
  }
}

/**
 * PUT /api/settings/proxy — update proxy configuration
 * Body: { level, id?, proxy } or legacy { global?, providers? }
 */
export async function PUT(request) {
  try {
    const body = await request.json();
    const normalizedBody = normalizeProxyPayload(body);
    const updated = await setProxyConfig(normalizedBody);
    clearDispatcherCache();
    return Response.json(updated);
  } catch (error) {
    const status = Number(error?.status) || 500;
    const type = error?.type || (status === 400 ? "invalid_request" : "server_error");
    return Response.json({ error: { message: error.message, type } }, { status });
  }
}

/**
 * DELETE /api/settings/proxy — remove proxy at a level
 * Query: ?level=provider&id=xxx
 */
export async function DELETE(request) {
  try {
    const { searchParams } = new URL(request.url);
    const level = searchParams.get("level");
    const id = searchParams.get("id");

    if (!level) {
      return Response.json(
        { error: { message: "level is required", type: "invalid_request" } },
        { status: 400 }
      );
    }

    const updated = await deleteProxyForLevel(level, id);
    clearDispatcherCache();
    return Response.json(updated);
  } catch (error) {
    return Response.json(
      { error: { message: error.message, type: "server_error" } },
      { status: 500 }
    );
  }
}
