import 'server-only'

import { cookies } from 'next/headers'
import { SignJWT, jwtVerify } from 'jose'
import type { UserRole } from '@/types/db'

/** Signed-cookie sessions for .env-based auth. */

export const SESSION_COOKIE = 'hha_session'
const SESSION_DAYS = 7

export interface SessionPayload {
  sub: string // user id (derived from email)
  email: string
  name: string
  role: UserRole
  company: string | null
  /**
   * True when the person who SIGNED IN is internal staff (Task 96).
   * Carried separately from `role` because the pilot role switch replaces
   * `role` with the previewed account: an admin who switches to the driver
   * test account must keep the bar that switches them back, while a customer
   * who signs in as a driver must never see it.
   */
  internal?: boolean
  /**
   * The account that actually SIGNED IN. Equals `sub` for a normal sign-in;
   * for a pilot role switch it is the admin who switched, so revoking that
   * admin also ends the session they switched into.
   */
  origin_sub?: string
  /** Issued-at, seconds — set by jose; compared against revocation. */
  iat?: number
  [key: string]: unknown
}

function secretKey(): Uint8Array {
  const secret = process.env.AUTH_SECRET
  if (!secret || secret.length < 16) {
    throw new Error('AUTH_SECRET must be set to a random string of at least 16 characters.')
  }
  return new TextEncoder().encode(secret)
}

export async function createSessionToken(payload: SessionPayload): Promise<string> {
  return new SignJWT(payload)
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime(`${SESSION_DAYS}d`)
    .sign(secretKey())
}

export async function verifySessionToken(token: string): Promise<SessionPayload | null> {
  try {
    const { payload } = await jwtVerify(token, secretKey())
    if (!payload.sub || !payload.email) return null
    return payload as unknown as SessionPayload
  } catch {
    return null
  }
}

export async function setSessionCookie(payload: SessionPayload) {
  const token = await createSessionToken(payload)
  const store = await cookies()
  store.set(SESSION_COOKIE, token, {
    httpOnly: true,
    sameSite: 'lax',
    secure: process.env.NODE_ENV === 'production',
    path: '/',
    maxAge: SESSION_DAYS * 24 * 3600,
  })
}

export async function clearSessionCookie() {
  const store = await cookies()
  store.delete(SESSION_COOKIE)
}

export async function readSession(): Promise<SessionPayload | null> {
  const store = await cookies()
  const token = store.get(SESSION_COOKIE)?.value
  if (!token) return null
  return verifySessionToken(token)
}
