/**
 * 认证模块
 * 支持：
 * 1. 账号密码登录（环境变量 + 数据库）
 * 2. OpenID Connect (OIDC)
 *
 * Session 存储在 Redis，Cookie 传输
 */
import { v4 as uuidv4 } from "uuid";
import bcrypt from "bcrypt";
import * as jose from "jose";
import {
  ADMIN_SESSION_COOKIE_NAME,
  ADMIN_SESSION_TTL,
  OIDC_ENABLED,
  OIDC_ISSUER,
  OIDC_CLIENT_ID,
  OIDC_CLIENT_SECRET,
  OIDC_REDIRECT_URI,
  ADMIN_SUPER_USERNAME,
  ADMIN_SUPER_PASSWORD,
  ADMIN_SUPER_PASSWORD_HASH,
  COOKIE_SECURE,
  COOKIE_SAME_SITE,
} from "./env";
import { saveSession, loadSession, deleteSession, refreshSessionTtl } from "./redis";
import {
  getUserByUsername,
  getAdminSession,
  createUser,
  type AdminSession,
} from "./rbac";
import type { AdminUser } from "./rbac";

const SALT_ROUNDS = 12;

// ============ 密码验证 ============

export async function verifyPassword(
  plain: string,
  hash: string
): Promise<boolean> {
  return bcrypt.compare(plain, hash);
}

export async function hashPassword(plain: string): Promise<string> {
  return bcrypt.hash(plain, SALT_ROUNDS);
}

// ============ 环境变量超级管理员 ============

async function verifySuperAdmin(
  username: string,
  password: string
): Promise<AdminUser | null> {
  if (
    !ADMIN_SUPER_USERNAME ||
    username !== ADMIN_SUPER_USERNAME
  ) {
    return null;
  }

  // 优先使用预哈希密码
  if (ADMIN_SUPER_PASSWORD_HASH) {
    const valid = await bcrypt.compare(password, ADMIN_SUPER_PASSWORD_HASH);
    if (!valid) return null;
  } else if (ADMIN_SUPER_PASSWORD) {
    if (password !== ADMIN_SUPER_PASSWORD) return null;
  } else {
    return null;
  }

  // 返回虚超级管理员用户对象（ID=-1）
  return {
    id: -1,
    username: ADMIN_SUPER_USERNAME,
    password_hash: ADMIN_SUPER_PASSWORD_HASH,
    is_active: true,
    created_at: new Date(),
    updated_at: new Date(),
  } as AdminUser;
}

// ============ 登录 ============

export async function login(
  username: string,
  password: string
): Promise<{ sessionId: string; adminSession: AdminSession } | null> {
  // 1. 尝试超级管理员
  const superUser = await verifySuperAdmin(username, password);
  let adminUser: AdminUser | null = superUser;
  let isSuperUser = !!superUser;

  // 2. 尝试数据库用户
  if (!adminUser) {
    const dbUser = await getUserByUsername(username);
    if (!dbUser || !dbUser.is_active) return null;

    const valid = await verifyPassword(password, dbUser.password_hash);
    if (!valid) return null;

    adminUser = dbUser;
    isSuperUser = false;
  }

  // 3. 生成 session
  const sessionId = uuidv4();
  const now = new Date().toISOString();

  // 获取权限信息
  let adminSession: AdminSession;
  if (isSuperUser) {
    adminSession = {
      userId: adminUser.id,
      username: adminUser.username,
      roles: ["super_admin"],
      permissions: ["*"], // 超级管理员拥有所有权限
    };
  } else {
    adminSession = await getAdminSession(adminUser.id, adminUser.username);
  }

  // 4. 保存到 Redis
  const sessionState: Record<string, unknown> = {
    "session:user_uid": adminUser.id,
    "session:username": adminUser.username,
    "session:roles": adminSession.roles,
    "session:permissions": adminSession.permissions,
    "session:created_at": now,
    "session:last_active": now,
    "session:ip_address": null,
    "session:user_agent": null,
  };

  await saveSession(sessionId, sessionState, ADMIN_SESSION_TTL);

  return { sessionId, adminSession };
}

// ============ Session 加载 ============

export async function loadAdminSession(
  sessionId: string
): Promise<AdminSession | null> {
  const state = await loadSession(sessionId);
  if (!state) return null;

  const userId = state["session:user_uid"];
  const username = state["session:username"] as string;
  const roles = (state["session:roles"] as string[]) || [];
  const permissions = (state["session:permissions"] as string[]) || [];

  if (!userId || !username) return null;

  return {
    userId: userId as number,
    username,
    roles,
    permissions,
  };
}

// ============ 刷新活跃时间 ============

export async function touchSession(sessionId: string): Promise<void> {
  const state = await loadSession(sessionId);
  if (!state) return;
  state["session:last_active"] = new Date().toISOString();
  const { saveSession } = await import("@/lib/redis");
  await saveSession(sessionId, state, ADMIN_SESSION_TTL);
}

// ============ 登出 ============

export async function logout(sessionId: string): Promise<void> {
  await deleteSession(sessionId);
}

// ============ OIDC ============

export function isOidcEnabled(): boolean {
  return (
    OIDC_ENABLED &&
    !!OIDC_ISSUER &&
    !!OIDC_CLIENT_ID &&
    !!OIDC_CLIENT_SECRET
  );
}

export function buildOidcAuthUrl(): string {
  const params = new URLSearchParams({
    client_id: OIDC_CLIENT_ID,
    redirect_uri: OIDC_REDIRECT_URI,
    response_type: "code",
    scope: "openid profile email",
  });
  return `${OIDC_ISSUER}/authorize?${params.toString()}`;
}

export async function exchangeOidcCode(
  code: string
): Promise<{ sessionId: string; adminSession: AdminSession } | null> {
  try {
    // 1. 用 code 换 token
    const tokenRes = await fetch(`${OIDC_ISSUER}/token`, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        grant_type: "authorization_code",
        code,
        redirect_uri: OIDC_REDIRECT_URI,
        client_id: OIDC_CLIENT_ID,
        client_secret: OIDC_CLIENT_SECRET,
      }),
    });

    if (!tokenRes.ok) return null;
    const tokenData = await tokenRes.json() as {
      access_token?: string;
      id_token?: string;
    };

    const idToken = tokenData.id_token || tokenData.access_token;
    if (!idToken) return null;

    // 2. 验证并解码 id_token
    const JWKS = jose.createRemoteJWKSet(
      new URL(`${OIDC_ISSUER}/.well-known/jwks.json`)
    );

    const { payload } = await jose.jwtVerify(idToken, JWKS, {
      issuer: OIDC_ISSUER,
      audience: OIDC_CLIENT_ID,
    });

    const email = payload.email as string;
    const name = (payload.name || payload.preferred_username || email) as string;

    // 3. 查找或创建 admin 用户
    let user = await getUserByUsername(email);
    if (!user) {
      // 自动创建（首次 OIDC 登录）
      const randomPassword = uuidv4();
      const passwordHash = await hashPassword(randomPassword);
      user = await createUser(email, passwordHash);
    }

    if (!user.is_active) return null;

    // 4. 生成 session
    const sessionId = uuidv4();
    const now = new Date().toISOString();
    const adminSession = await getAdminSession(user.id, user.username);

    const sessionState: Record<string, unknown> = {
      "session:user_uid": user.id,
      "session:username": user.username,
      "session:roles": adminSession.roles,
      "session:permissions": adminSession.permissions,
      "session:created_at": now,
      "session:last_active": now,
      "session:oidc_name": name,
      "session:ip_address": null,
      "session:user_agent": null,
    };

    await saveSession(sessionId, sessionState, ADMIN_SESSION_TTL);

    return { sessionId, adminSession };
  } catch {
    return null;
  }
}

// ============ Cookie 工具 ============

export interface CookieOptions {
  maxAge?: number;
  path?: string;
  domain?: string;
  sameSite?: "strict" | "lax" | "none";
  httpOnly?: boolean;
  secure?: boolean;
}

export function buildSetCookieHeader(
  value: string,
  options: CookieOptions = {}
): string {
  const {
    maxAge = ADMIN_SESSION_TTL,
    path = "/",
    sameSite = COOKIE_SAME_SITE,
    httpOnly = true,
    secure = COOKIE_SECURE,
  } = options;

  let cookie = `${ADMIN_SESSION_COOKIE_NAME}=${encodeURIComponent(value)}; Path=${path}; Max-Age=${maxAge}; SameSite=${sameSite}`;

  if (secure) cookie += "; Secure";
  if (httpOnly) cookie += "; HttpOnly";

  return cookie;
}

export function parseSessionCookie(cookieHeader: string | null): string | null {
  if (!cookieHeader) return null;
  const cookies = cookieHeader.split(";").map((c) => c.trim());
  for (const cookie of cookies) {
    const [name, ...valueParts] = cookie.split("=");
    if (name === ADMIN_SESSION_COOKIE_NAME) {
      return decodeURIComponent(valueParts.join("="));
    }
  }
  return null;
}

export function buildClearCookieHeader(): string {
  return `${ADMIN_SESSION_COOKIE_NAME}=; Path=/; Max-Age=0; SameSite=${COOKIE_SAME_SITE}${COOKIE_SECURE ? "; Secure" : ""}; HttpOnly`;
}

// ============ 权限检查 ============

export function canAccess(
  session: AdminSession | null,
  requiredPermission: string
): boolean {
  if (!session) return false;
  if (session.permissions.includes("*")) return true;
  return session.permissions.includes(requiredPermission);
}

export function isSuperAdmin(session: AdminSession | null): boolean {
  return session?.roles.includes("super_admin") ?? false;
}

/** 从 NextRequest headers 提取当前登录的 admin user id（由 middleware 设置） */
export function getAdminUserId(req: Request): number | null {
  const header = req.headers.get("x-admin-user-id");
  if (!header) return null;
  const id = parseInt(header, 10);
  return isNaN(id) ? null : id;
}
