/**
 * Next.js Middleware
 * 1. 前端路由保护（未登录重定向）
 * 2. API 路由权限控制（RBAC + API Token）
 *
 * 使用 Node.js Runtime 以支持 bcrypt/ioredis/crypto
 */
export const runtime = "nodejs";

import { NextRequest, NextResponse } from "next/server";
import { createHash } from "crypto";
import { parseSessionCookie, loadAdminSession, canAccess } from "@/lib/auth";
import { query } from "@/lib/db";

const PUBLIC_PATHS = ["/login", "/api/auth/login", "/api/auth/oidc", "/api/health", "/api/metrics/prometheus"];
const PROTECTED_PATHS = ["/dashboard", "/admin", "/platform"];

function getRequiredPermission(path: string, method: string): string | null {
  if (path.startsWith("/api/users")) {
    if (method === "GET") return "user:read";
    if (method === "POST") return "user:create";
    if (method === "PUT" || method === "PATCH") return "user:update";
    if (method === "DELETE") return "user:delete";
  }
  if (path.startsWith("/api/roles")) {
    if (method === "GET") return "role:read";
    if (method === "POST") return "role:create";
    if (method === "PUT" || method === "PATCH") return "role:update";
    if (method === "DELETE") return "role:delete";
  }
  if (path.startsWith("/api/permissions")) {
    if (method === "GET") return "permission:read";
    if (method === "POST") return "permission:create";
    if (method === "PUT" || method === "PATCH") return "permission:update";
    if (method === "DELETE") return "permission:delete";
  }
  if (path.startsWith("/api/logs")) {
    if (method === "GET") return "log:read";
  }
  if (path.startsWith("/api/sessions")) {
    return "session:manage";
  }
  if (path.startsWith("/api/platform")) {
    if (method === "GET") return "platform:read";
    return "platform:manage";
  }
  if (path.startsWith("/api/admin/projects")) {
    if (method === "GET") return "platform:read";
    return "platform:manage";
  }
  if (path.startsWith("/api/metrics")) {
    if (method === "GET") return "platform:read";
    return "platform:manage";
  }
  if (path.startsWith("/api/api-tokens")) {
    return null; // Token 管理需要 session，不允许 token 访问自己
  }
  return null;
}

/** 从 Authorization: Bearer <token> 验证 API Token */
async function verifyApiToken(req: NextRequest): Promise<
  { valid: true; tokenId: number; permissions: string[] } |
  { valid: false }
> {
  const authHeader = req.headers.get("Authorization");
  if (!authHeader?.startsWith("Bearer ")) return { valid: false };

  const token = authHeader.slice("Bearer ".length);
  if (!token) return { valid: false };

  try {
    const hash = createHash("sha256").update(token).digest("hex");
    const result = await query<{
      id: number;
      permissions: string[];
      is_active: boolean;
      expires_at: Date | null;
    }>(
      `SELECT id, permissions, is_active, expires_at FROM admin_api_token WHERE token_hash = $1`,
      [hash]
    );

    if (!result.rows.length) return { valid: false };
    const row = result.rows[0];
    if (!row.is_active) return { valid: false };
    if (row.expires_at && new Date(row.expires_at) < new Date()) return { valid: false };

    // 更新 last_used_at（fire-and-forget）
    query(`UPDATE admin_api_token SET last_used_at = NOW() WHERE id = $1`, [row.id]).catch(() => {});

    return { valid: true, tokenId: row.id, permissions: row.permissions || [] };
  } catch {
    return { valid: false };
  }
}

export async function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl;
  const method = req.method;

  // 静态资源跳过
  if (
    pathname.startsWith("/_next") ||
    pathname.startsWith("/favicon") ||
    pathname.endsWith(".ico") ||
    pathname.endsWith(".png") ||
    pathname.endsWith(".svg")
  ) {
    return NextResponse.next();
  }

  // 公开路由放行
  if (PUBLIC_PATHS.some((p) => pathname.startsWith(p))) {
    return NextResponse.next();
  }

  // ========== API 路由权限控制 ==========
  if (pathname.startsWith("/api/")) {
    const headers = new Headers(req.headers);
    let authType: "session" | "token" = "session";
    let permissions: string[] = [];

    // 优先尝试 API Token 认证
    const tokenResult = await verifyApiToken(req);
    if (tokenResult.valid) {
      authType = "token";
      permissions = tokenResult.permissions || [];
      headers.set("x-admin-auth-type", "token");
      headers.set("x-admin-token-id", String(tokenResult.tokenId));
      headers.set("x-admin-permissions", permissions.join(","));
    } else {
      // 回退到 Session 认证
      const cookieHeader = req.headers.get("cookie");
      const sessionId = parseSessionCookie(cookieHeader);

      if (!sessionId) {
        return NextResponse.json({ error: "未登录或未提供 API Token" }, { status: 401 });
      }

      const session = await loadAdminSession(sessionId);
      if (!session) {
        return NextResponse.json({ error: "会话已过期" }, { status: 401 });
      }

      headers.set("x-admin-user-id", String(session.userId));
      headers.set("x-admin-username", session.username);
      headers.set("x-admin-permissions", session.permissions.join(","));
      permissions = session.permissions;
    }

    const requiredPermission = getRequiredPermission(pathname, method);
    if (requiredPermission && !permissions.some((p) => p === "*" || p === requiredPermission)) {
      return NextResponse.json({ error: "权限不足" }, { status: 403 });
    }

    return NextResponse.next({ request: { headers } });
  }

  // ========== 前端页面保护（仅 Session） ==========
  if (PROTECTED_PATHS.some((p) => pathname.startsWith(p))) {
    const cookieHeader = req.headers.get("cookie");
    const sessionCookie = cookieHeader
      ?.split(";")
      .find((c) => c.trim().startsWith("admin_session="));

    if (!sessionCookie) {
      return NextResponse.redirect(new URL("/login", req.url));
    }
  }

  return NextResponse.next();
}

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