/**
 * The authoritative "who is asking" lookup.
 *
 * Permissions are re-read from the database rather than trusted from the token, so a role
 * change takes effect on the user's next request instead of at their next login. The
 * result is memoised per request with React's `cache`, so a page that checks several
 * permissions still performs exactly one query.
 */

import 'server-only'

import { cache } from 'react'

import { prisma } from '../db'
import type { Locale } from '../domain/enums'
import { readSessionCookie, verifySession } from './session'

export interface CurrentUser {
  id: string
  email: string
  name: string
  nameAr: string
  employeeId: string
  department: string
  departmentAr: string
  locale: Locale
  roles: string[]
  roleNames: Array<{ key: string; name: string; nameAr: string; level: number }>
  permissions: Set<string>
  /** Highest role level held — used to order role-specific landing pages. */
  level: number
  sessionId: string
}

export const getCurrentUser = cache(async (): Promise<CurrentUser | null> => {
  const token = await readSessionCookie()
  if (!token) return null

  const payload = await verifySession(token)
  if (!payload) return null

  const session = await prisma.session.findUnique({
    where: { tokenId: payload.jti },
    include: {
      user: {
        include: { roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } } },
      },
    },
  })

  // A token whose session row is gone, revoked or expired is not a session.
  if (!session || session.revokedAt || session.expiresAt.getTime() < Date.now()) return null
  if (!session.user.isActive) return null

  const permissions = new Set<string>()
  for (const link of session.user.roles) {
    for (const grant of link.role.permissions) permissions.add(grant.permission.key)
  }

  return {
    id: session.user.id,
    email: session.user.email,
    name: session.user.name,
    nameAr: session.user.nameAr,
    employeeId: session.user.employeeId,
    department: session.user.department,
    departmentAr: session.user.departmentAr,
    locale: (session.user.locale === 'en' ? 'en' : 'ar') as Locale,
    roles: session.user.roles.map((r) => r.role.key),
    roleNames: session.user.roles.map((r) => ({
      key: r.role.key,
      name: r.role.name,
      nameAr: r.role.nameAr,
      level: r.role.level,
    })),
    permissions,
    level: session.user.roles.reduce((max, r) => Math.max(max, r.role.level), 0),
    sessionId: session.id,
  }
})

export function can(user: CurrentUser | null, permission: string): boolean {
  return user?.permissions.has(permission) ?? false
}

export function canAny(user: CurrentUser | null, permissions: string[]): boolean {
  return permissions.some((p) => can(user, p))
}

/** The landing page each role should see first (§21 vs §22). */
export function homePathFor(user: CurrentUser | null): string {
  if (!user) return '/login'
  if (user.roles.includes('executive')) return '/executive'
  if (user.roles.includes('maintenance_engineer')) return '/maintenance'
  if (user.roles.includes('viewer')) return '/grid'
  return '/command-center'
}
