import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import { getToken } from "next-auth/jwt"

import { type Permission } from "@/shared/types/permissions"
import { resolveDefaultPath } from "@/shared/lib/route-resolver"
import { hasPermissionInBitmap } from "@/shared/lib/permission-bitmap"
import {
  SPECIFIC_ROUTE_PERMISSIONS,
  ROUTE_PREFIX_PERMISSIONS,
  DASHBOARD_ROUTE_PERMISSIONS,
  API_ROUTE_PERMISSIONS,
} from "@/shared/lib/route-permissions"

// Next.js 16 renamed `middleware` to `proxy`.
// See: https://nextjs.org/docs/messages/middleware-to-proxy
export async function proxy(request: NextRequest) {
  const { pathname } = request.nextUrl

  // Skip static assets and auth pages
  if (
    pathname.startsWith("/_next") ||
    pathname.startsWith("/api/auth") ||
    pathname === "/login" ||
    pathname === "/register" ||
    pathname === "/favicon.ico"
  ) {
    return NextResponse.next()
  }

  const token = await getToken({
    req: request,
    secret: process.env.NEXTAUTH_SECRET,
  })

  // Not authenticated → redirect to login
  if (!token) {
    const loginUrl = new URL("/login", request.url)
    loginUrl.searchParams.set("callbackUrl", request.url)
    return NextResponse.redirect(loginUrl)
  }

  // Onboarding gate: 未完成引导的用户只能访问 /onboarding 与白名单路径
  // 修复 P2-1：用 middleware 强制重定向替代客户端 Dialog
  const onboarded = Boolean(token.onboarded)
  const isOnboardingPath = pathname === "/onboarding" || pathname.startsWith("/onboarding/")
  const isWhitelistedApi = pathname.startsWith("/api/auth") || pathname.startsWith("/api/onboarding")
  if (!onboarded && !isOnboardingPath && !isWhitelistedApi) {
    const onboardingUrl = new URL("/onboarding", request.url)
    return NextResponse.redirect(onboardingUrl)
  }
  // 已完成 onboarding 的用户不应停留在 /onboarding
  if (onboarded && isOnboardingPath) {
    const roles: string[] = (token.roles as string[]) ?? []
    const defaultPath = resolveDefaultPath(roles)
    return NextResponse.redirect(new URL(defaultPath, request.url))
  }

  const permissionsBitmap: string = (token.permissionsBitmap as string) ?? ""
  const roles: string[] = (token.roles as string[]) ?? []

  /**
   * audit-P1-7：使用位图检查权限，避免每次路由检查都解码完整权限数组。
   * proxy.ts 在 edge runtime 运行，每个请求都经过这里，性能至关重要。
   */
  function hasPermission(requiredPerm: Permission): boolean {
    return hasPermissionInBitmap(permissionsBitmap, requiredPerm)
  }

  // Check API route permissions
  for (const [prefix, requiredPerm] of Object.entries(API_ROUTE_PERMISSIONS)) {
    if (pathname.startsWith(prefix)) {
      if (!hasPermission(requiredPerm)) {
        return NextResponse.json({ error: "Forbidden" }, { status: 403 })
      }
      break
    }
  }

  // Check page route permissions
  // 优先级 1：精确路由权限（覆盖前缀匹配，用于将 /admin/* 下特定页面开放给非管理员）
  if (Object.prototype.hasOwnProperty.call(SPECIFIC_ROUTE_PERMISSIONS, pathname)) {
    const requiredPerm = SPECIFIC_ROUTE_PERMISSIONS[pathname]
    if (!hasPermission(requiredPerm)) {
      const defaultPath = resolveDefaultPath(roles)
      const redirectUrl = new URL(defaultPath, request.url)
      redirectUrl.searchParams.set("from", pathname)
      redirectUrl.searchParams.set("reason", "forbidden")
      return NextResponse.redirect(redirectUrl)
    }
    return NextResponse.next()
  }

  // 优先级 2：仪表盘路由的细粒度权限（防止跨角色访问仪表盘）
  if (Object.prototype.hasOwnProperty.call(DASHBOARD_ROUTE_PERMISSIONS, pathname)) {
    const requiredPerm = DASHBOARD_ROUTE_PERMISSIONS[pathname]
    if (!hasPermission(requiredPerm)) {
      const defaultPath = resolveDefaultPath(roles)
      const redirectUrl = new URL(defaultPath, request.url)
      redirectUrl.searchParams.set("from", pathname)
      redirectUrl.searchParams.set("reason", "forbidden")
      return NextResponse.redirect(redirectUrl)
    }
    return NextResponse.next()
  }

  for (const [prefix, requiredPerm] of Object.entries(ROUTE_PREFIX_PERMISSIONS)) {
    if (pathname.startsWith(prefix)) {
      if (!hasPermission(requiredPerm)) {
        const defaultPath = resolveDefaultPath(roles)
        // Carry original path + reason in URL so the target page can explain
        // why the user was redirected (Web Interface Guidelines: URL reflects state).
        const redirectUrl = new URL(defaultPath, request.url)
        redirectUrl.searchParams.set("from", pathname)
        redirectUrl.searchParams.set("reason", "forbidden")
        return NextResponse.redirect(redirectUrl)
      }
      break
    }
  }

  return NextResponse.next()
}

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
}
