import { NextRequest } from "next/server";
import { NetworkSecurityInfo } from "./db";

export type NetworkSecurityResult = NetworkSecurityInfo;

// 30-minute in-memory cache to prevent repeated external queries
const networkCache = new Map<string, { result: NetworkSecurityResult; expiresAt: number }>();
const CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes

/**
 * Extracts and verifies the trusted client IP address from platform headers.
 * Resolves in order:
 *  1. Cloudflare: cf-connecting-ip
 *  2. Vercel: x-vercel-forwarded-for
 *  3. Standard: x-real-ip
 *  4. Standard: x-forwarded-for (first client IP in comma-separated chain)
 */
export function resolveClientIp(req?: NextRequest | Request): string {
  if (!req) return "127.0.0.1";

  const headers = req.headers;
  const cfIp = headers.get("cf-connecting-ip");
  if (cfIp) return cfIp.trim();

  const vercelIp = headers.get("x-vercel-forwarded-for");
  if (vercelIp) return vercelIp.split(",")[0].trim();

  const realIp = headers.get("x-real-ip");
  if (realIp) return realIp.trim();

  const forwardedFor = headers.get("x-forwarded-for");
  if (forwardedFor) {
    const first = forwardedFor.split(",")[0].trim();
    if (first) return first;
  }

  return "127.0.0.1";
}

/**
 * Checks if an IP is a private loopback, local development, or RFC1918 address.
 */
export function isPrivateOrLocalIp(ip: string | null): boolean {
  if (!ip) return true;
  const trimmed = ip.trim().toLowerCase();
  if (
    trimmed === "127.0.0.1" ||
    trimmed === "::1" ||
    trimmed === "localhost" ||
    trimmed === "::ffff:127.0.0.1"
  ) {
    return true;
  }
  if (trimmed.startsWith("10.") || trimmed.startsWith("192.168.")) return true;
  if (/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(trimmed)) return true;
  if (trimmed.startsWith("fc") || trimmed.startsWith("fd") || trimmed.startsWith("fe80")) return true;
  return false;
}

/**
 * Server-Side Network Security & VPN / Proxy / Tor / Relay Detection Abstraction
 *
 * Implements Part 9-26:
 *  - Real server-side incoming network identity
 *  - Pluggable provider architecture (VPNAPI.io default)
 *  - High-performance 30-minute caching
 *  - Simulated test hooks for reliable automated auditing
 */
export async function getNetworkSecurity(
  ip: string,
  req?: NextRequest | Request
): Promise<NetworkSecurityResult> {
  const cleanIp = (ip || "127.0.0.1").trim();
  const now = Date.now();

  // 1. Simulation Check (for deterministic automated security tests)
  const simHeader = req?.headers.get("x-simulate-vpn") || process.env.SIMULATE_VPN;
  if (simHeader === "true" || simHeader === "vpn" || simHeader === "proxy" || simHeader === "tor") {
    const isTor = simHeader === "tor";
    const isProxy = simHeader === "proxy";
    const isVpn = !isTor && !isProxy;
    return {
      ip: cleanIp,
      isVpn,
      isProxy,
      isTor,
      isRelay: false,
      isBlocked: true,
      blockReason: isTor
        ? "Tor exit node network traffic detected"
        : isProxy
        ? "Anonymous proxy connection detected"
        : "Commercial VPN connection detected",
      risk: "HIGH",
      asn: "AS13335 (Simulated Security Check)",
      country: "US",
      city: "San Jose",
      provider: "vpnapi.io-simulated",
      checkedAt: new Date().toISOString(),
    };
  }

  // 2. Cache Lookup
  const cached = networkCache.get(cleanIp);
  if (cached && cached.expiresAt > now) {
    return cached.result;
  }

  // 3. Local / Private Development IP bypass
  if (isPrivateOrLocalIp(cleanIp)) {
    const localResult: NetworkSecurityResult = {
      ip: cleanIp,
      isVpn: false,
      isProxy: false,
      isTor: false,
      isRelay: false,
      isBlocked: false,
      blockReason: null,
      risk: "LOW",
      asn: "Localhost Development",
      country: "Local",
      city: "Localhost",
      provider: "local-dev",
      checkedAt: new Date().toISOString(),
    };
    networkCache.set(cleanIp, { result: localResult, expiresAt: now + CACHE_TTL_MS });
    return localResult;
  }

  // 4. External Provider Check (VPNAPI.io)
  const apiKey = process.env.VPNAPI_KEY || process.env.VPN_DETECTION_API_KEY;
  if (!apiKey) {
    // If no external key configured, log safe telemetry in dev/staging
    const noKeyResult: NetworkSecurityResult = {
      ip: cleanIp,
      isVpn: false,
      isProxy: false,
      isTor: false,
      isRelay: false,
      isBlocked: false,
      blockReason: null,
      risk: "LOW",
      provider: "vpnapi.io-unconfigured",
      checkedAt: new Date().toISOString(),
    };
    networkCache.set(cleanIp, { result: noKeyResult, expiresAt: now + CACHE_TTL_MS });
    return noKeyResult;
  }

  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 3500);

    const response = await fetch(`https://vpnapi.io/api/${cleanIp}?key=${apiKey}`, {
      signal: controller.signal,
      cache: "no-store",
    });
    clearTimeout(timeout);

    if (!response.ok) {
      throw new Error(`VPNAPI.io responded with status ${response.status}`);
    }

    const data = await response.json();
    const isVpn = Boolean(data.security?.vpn);
    const isProxy = Boolean(data.security?.proxy);
    const isTor = Boolean(data.security?.tor);
    const isRelay = Boolean(data.security?.relay);
    const isBlocked = isVpn || isProxy || isTor || isRelay;

    let blockReason: string | null = null;
    if (isTor) blockReason = "Tor exit node network connection detected.";
    else if (isVpn) blockReason = "Commercial VPN tunnel detected.";
    else if (isProxy) blockReason = "Anonymous proxy server connection detected.";
    else if (isRelay) blockReason = "Private relay / anonymized network connection detected.";

    const result: NetworkSecurityResult = {
      ip: cleanIp,
      isVpn,
      isProxy,
      isTor,
      isRelay,
      isBlocked,
      blockReason,
      risk: isBlocked ? "HIGH" : "LOW",
      asn: data.network?.autonomous_system_number
        ? `${data.network.autonomous_system_number} (${data.network.autonomous_system_organization || ""})`
        : undefined,
      country: data.location?.country || undefined,
      city: data.location?.city || undefined,
      provider: "vpnapi.io",
      checkedAt: new Date().toISOString(),
    };

    networkCache.set(cleanIp, { result, expiresAt: now + CACHE_TTL_MS });
    return result;
  } catch (error: any) {
    console.error("[getNetworkSecurity] Provider query error:", error.message);

    // Fail-safe handling: If strict mode is enforced in production, indicate service unavailable
    if (process.env.NODE_ENV === "production" && process.env.STRICT_VPN_BLOCK === "true") {
      return {
        ip: cleanIp,
        isVpn: false,
        isProxy: false,
        isTor: false,
        isRelay: false,
        isBlocked: true,
        blockReason: "Network security verification temporarily unavailable. Please retry.",
        risk: "HIGH",
        provider: "vpnapi.io-error",
        checkedAt: new Date().toISOString(),
      };
    }

    // Default graceful fallback: allow access with audit alert
    return {
      ip: cleanIp,
      isVpn: false,
      isProxy: false,
      isTor: false,
      isRelay: false,
      isBlocked: false,
      blockReason: null,
      risk: "LOW",
      provider: "vpnapi.io-fallback",
      checkedAt: new Date().toISOString(),
    };
  }
}
