import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import { resolvePermissions } from "@/shared/lib/permissions"
import { isRole } from "@/shared/types/permissions"
import { logLoginEvent } from "@/shared/lib/login-logger"
import { normalizeRole, resolvePrimaryRole } from "@/shared/lib/role-utils"
import {
  encodePermissionsBitmap,
  decodePermissionsBitmap,
} from "@/shared/lib/permission-bitmap"
import { trackAuthEvent } from "@/shared/lib/track-event"

export const { handlers, auth, signIn, signOut } = NextAuth({
  trustHost: true,
  secret: process.env.NEXTAUTH_SECRET,
  session: { strategy: "jwt" },
  pages: { signIn: "/login" },
  providers: [
    Credentials({
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
        totpCode: { label: "2FA Code", type: "text" },
      },
      // audit-P1-3 重构：authorize 回调原混合 7 类职责（107 行），
      // 已抽取至 modules/auth/services/login-service.ts 的 authenticateUser 函数。
      // 此处为薄包装，仅负责动态 import（避免 server-only 模块在模块评估期加载）
      // 与委托调用。所有登录逻辑（速率限制/账户锁定/密码校验/2FA/角色加载）均在
      // login-service 中实现，可独立测试。
      authorize: async (credentials) => {
        const { authenticateUser } = await import("@/modules/auth/services/login-service")
        return authenticateUser(credentials)
      },
    }),
  ],
  callbacks: {
    jwt: async ({ token, user }) => {
      // P0-5 修复：User 接口已在 next-auth.d.ts 中扩展了 role/roles 字段，
      // 无需 `as` 断言即可安全访问。
      if (user && user.id) {
        token.id = user.id
        token.role = normalizeRole(user.role)
        token.name = user.name ?? undefined
        // Store all roles (not just primary) and resolved permissions
        const allRoles = (user.roles ?? [user.role ?? "student"]).filter(isRole)
        token.roles = allRoles
        // audit-P1-7：JWT 中仅存位图（~14 字符），不存数组（~1.1KB）。
        // Session callback 解码还原为 Permission[] 供业务使用。
        const permissions = await resolvePermissions(allRoles)
        token.permissionsBitmap = encodePermissionsBitmap(permissions)
        // Onboarding status is resolved from DB below; default to false on first login
        token.onboarded = false
      }

      // Refresh roles/permissions from DB on each JWT refresh
      const userId = String(token.id ?? "").trim()
      if (userId) {
        const [{ eq }, { db }, { roles, users, usersToRoles }] = await Promise.all([
          import("drizzle-orm"),
          import("@/shared/db"),
          import("@/shared/db/schema"),
        ])

        const [fresh, roleRows] = await Promise.all([
          db.query.users.findFirst({
            where: eq(users.id, userId),
            columns: { name: true, onboardedAt: true },
          }),
          db
            .select({ name: roles.name })
            .from(usersToRoles)
            .innerJoin(roles, eq(usersToRoles.roleId, roles.id))
            .where(eq(usersToRoles.userId, userId)),
        ])

        if (fresh) {
          const allRoles = roleRows.map((r) => r.name).filter(isRole)
          token.role = resolvePrimaryRole(allRoles)
          token.name = fresh.name ?? token.name
          token.roles = allRoles
          // audit-P1-7：刷新位图，不再写 token.permissions 数组
          const permissions = await resolvePermissions(allRoles)
          token.permissionsBitmap = encodePermissionsBitmap(permissions)
          token.onboarded = Boolean(fresh.onboardedAt)
        }
      }

      return token
    },
    session: async ({ session, token }) => {
      // audit-P1-7：session.user.permissions 由位图解码得到，
      // 业务代码（getAuthContext / usePermission）无需感知位图存在。
      if (session.user) {
        session.user.id = String(token.id ?? "")
        session.user.role = normalizeRole(token.role)
        session.user.roles = (token.roles ?? []).filter(isRole)
        session.user.permissions = decodePermissionsBitmap(
          token.permissionsBitmap ?? "",
        )
        session.user.onboarded = Boolean(token.onboarded)
        if (typeof token.name === "string") {
          session.user.name = token.name
        }
      }
      return session
    },
  },
  events: {
    async signIn({ user }) {
      await logLoginEvent({
        userId: user.id,
        userEmail: user.email ?? "",
        action: "signin",
        status: "success",
      })
      // audit-P1-9：登录成功埋点（用于登录成功率、异常登录地理/设备告警）
      // 非阻塞：trackEvent 内部已吞掉异常
      await trackAuthEvent("auth.signin_success", {
        userId: user.id,
        properties: {
          // user.role 是单一主角色，user.roles 是全部角色（可能未填充）
          roles: (user.roles ?? (user.role ? [user.role] : [])),
        },
      })
    },
    async signOut(message) {
      // P0-5 修复：使用 `in` 操作符对联合类型进行类型收窄，替代 `as` 断言。
      // NextAuth v5 signOut 事件 message 为联合类型：
      //   { session: ... } | { token: JWT }
      // JWT 策略下实际收到 { token: JWT }，其中 JWT 已在 next-auth.d.ts 扩展。
      let userId = ""
      let userEmail = ""
      let roles: string[] = []

      if ("token" in message) {
        const token = message.token
        if (token) {
          userId = String(token.id ?? "")
          userEmail = String(token.email ?? "")
          roles = (token.roles ?? []).filter(isRole)
        }
      }

      if (userEmail) {
        await logLoginEvent({
          userId: userId || undefined,
          userEmail,
          action: "signout",
          status: "success",
        })
      }
      // audit-P1-9：登出埋点
      if (userId) {
        await trackAuthEvent("auth.signout", {
          userId,
          properties: { roles },
        })
      }
    },
  },
})
