import { NextRequest, NextResponse } from 'next/server'
import { looksLikeJwt } from '@/lib/security-edge'
import {
  isBadBot,
  isAttackPath,
  isInjectionAttempt,
  edgeRateLimit,
} from '@/lib/firewall-edge'

// ── Security response headers ────────────────────────────────────────────────
// Applied to every response that passes the firewall checks.

const SECURITY_HEADERS: Record<string, string> = {
  // Prevent embedding in iframes (clickjacking)
  'X-Frame-Options': 'DENY',
  // Prevent MIME-type sniffing
  'X-Content-Type-Options': 'nosniff',
  // Limit referrer information sent cross-origin
  'Referrer-Policy': 'strict-origin-when-cross-origin',
  // Disable browser features not needed by this site
  'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), payment=()',
  // Force HTTPS for 1 year (only meaningful in production, but harmless in dev)
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
  // Legacy XSS filter (still honoured by some older browsers)
  'X-XSS-Protection': '1; mode=block',
  // Prevent cross-origin resource embedding
  'Cross-Origin-Resource-Policy': 'same-origin',
}

function addSecurityHeaders(res: NextResponse): NextResponse {
  for (const [k, v] of Object.entries(SECURITY_HEADERS)) {
    res.headers.set(k, v)
  }
  return res
}

// ── Firewall response helpers ────────────────────────────────────────────────

function block403(reason: string): NextResponse {
  return new NextResponse(
    `<!doctype html><html><head><title>403 Forbidden</title></head><body>
<h1>403 Forbidden</h1><p>Access denied.</p>
<small>ref: ${reason}</small></body></html>`,
    {
      status: 403,
      headers: {
        'Content-Type': 'text/html; charset=utf-8',
        ...SECURITY_HEADERS,
      },
    },
  )
}

function block429(): NextResponse {
  return new NextResponse(
    '<!doctype html><html><head><title>429 Too Many Requests</title></head><body>' +
    '<h1>429 Too Many Requests</h1><p>Slow down and try again later.</p></body></html>',
    {
      status: 429,
      headers: {
        'Content-Type': 'text/html; charset=utf-8',
        'Retry-After': '60',
        ...SECURITY_HEADERS,
      },
    },
  )
}

// ── Get client IP (edge-safe, no Node.js crypto) ────────────────────────────

function getEdgeIp(req: NextRequest): string {
  return (
    req.headers.get('x-nf-client-connection-ip') ??
    req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ??
    '0.0.0.0'
  )
}

// ── AI referrer detection (GEO/AEO tracking) ────────────────────────────────
//
// Detects when a visitor arrives from an AI search assistant (ChatGPT,
// Perplexity, Claude, Gemini, Copilot) so we can:
//  1. Set a non-HTTPOnly cookie so client components can render an
//     AI-inbound welcome banner ("We see you came from Claude…")
//  2. Track citation→click conversion in Clarity / Analytics via a custom
//     event when the cookie is first set
//
// The cookie name is `__ci_ai_src` — value is the canonical source slug.
// Cookie lifetime is 7 days (matches typical AI-research session length).

const AI_REFERRERS: Array<{ pattern: RegExp; source: string }> = [
  { pattern: /\bchat\.openai\.com$/i,     source: 'chatgpt'    },
  { pattern: /\bchatgpt\.com$/i,          source: 'chatgpt'    },
  { pattern: /\bperplexity\.ai$/i,        source: 'perplexity' },
  { pattern: /\.perplexity\.ai$/i,        source: 'perplexity' },
  { pattern: /\bclaude\.ai$/i,            source: 'claude'     },
  { pattern: /\bgemini\.google\.com$/i,   source: 'gemini'     },
  { pattern: /\baistudio\.google\.com$/i, source: 'gemini'     },
  { pattern: /\bcopilot\.microsoft\.com$/i, source: 'copilot'  },
  { pattern: /\bbing\.com\/copilot$/i,    source: 'copilot'    },
  { pattern: /\byou\.com$/i,              source: 'you'        },
  { pattern: /\bphind\.com$/i,            source: 'phind'      },
  { pattern: /\bkagi\.com$/i,             source: 'kagi'       },
]

function detectAiSource(req: NextRequest): string | null {
  const referer = req.headers.get('referer') ?? ''
  if (!referer) return null
  try {
    const host = new URL(referer).hostname.toLowerCase()
    for (const { pattern, source } of AI_REFERRERS) {
      if (pattern.test(host)) return source
    }
  } catch {
    // Malformed referer header — ignore
  }
  return null
}

function attachAiSourceCookie(res: NextResponse, source: string): NextResponse {
  // 7-day SameSite=Lax cookie. Client-readable (no HttpOnly) so the banner
  // component can read it. Path = root so all routes see it.
  res.cookies.set('__ci_ai_src', source, {
    maxAge: 60 * 60 * 24 * 7,
    sameSite: 'lax',
    secure: true,
    path: '/',
  })
  // Also surface in a response header — useful for server logs / analytics
  // tags that scrape headers rather than reading cookies.
  res.headers.set('x-ci-ai-source', source)
  return res
}

// ── Main middleware ──────────────────────────────────────────────────────────

export function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl
  const ua           = req.headers.get('user-agent') ?? ''
  const ip           = getEdgeIp(req)
  const isApi        = pathname.startsWith('/api/')

  // ── LAYER 1: Bad bot / scanner detection ────────────────────────────────
  if (ua && isBadBot(ua)) {
    return block403('bad-bot')
  }

  // ── LAYER 2: Known attack path detection ────────────────────────────────
  if (isAttackPath(pathname)) {
    return block403('attack-path')
  }

  // ── LAYER 3: Injection attempt in URL ───────────────────────────────────
  const rawUrl = req.nextUrl.search // query string (may contain payloads)
  if (rawUrl && isInjectionAttempt(rawUrl)) {
    return block403('injection')
  }
  // Also scan the path itself for path-traversal attempts
  if (isInjectionAttempt(pathname)) {
    return block403('injection-path')
  }

  // ── LAYER 4: Edge rate limiting ─────────────────────────────────────────
  // Only enforce in production — dev traffic should never be blocked.
  if (process.env.NODE_ENV === 'production' && edgeRateLimit(ip, isApi)) {
    return block429()
  }

  // ── LAYER 5: Portal authentication gate ─────────────────────────────────
  // (Unchanged from original middleware — guards /portal/* routes)
  const isPortalRoute = pathname.startsWith('/portal')
  const isAuthPage    =
    pathname === '/portal/login' ||
    pathname === '/portal/register' ||
    pathname === '/portal/setup'

  if (isPortalRoute && !isAuthPage) {
    const sessionCookie = req.cookies.get('portal_session')
    if (!sessionCookie?.value || !looksLikeJwt(sessionCookie.value)) {
      const loginUrl = req.nextUrl.clone()
      loginUrl.pathname = '/portal/login'
      loginUrl.searchParams.set('redirect', pathname)
      return NextResponse.redirect(loginUrl)
    }
  }

  // ── All checks passed — continue and attach headers/cookies ─────────────
  const res = addSecurityHeaders(NextResponse.next())

  // ── GEO TRACKING: tag inbound traffic from AI search assistants ─────────
  // Only set the cookie if it isn't already set in this session — avoids
  // overwriting on every navigation and keeps the original source intact.
  const aiSource = detectAiSource(req)
  if (aiSource && !req.cookies.get('__ci_ai_src')) {
    attachAiSourceCookie(res, aiSource)
  }

  return res
}

export const config = {
  matcher: [
    /*
     * Match every route EXCEPT:
     *  - /_next/static     (pre-built static chunks — no need to firewall)
     *  - /_next/image      (image optimisation responses)
     *  - /favicon.ico
     *
     * The firewall runs on all other pages and API routes.
     */
    '/((?!_next/static|_next/image|favicon\\.ico).*)',
  ],
}
