import jwt from 'jsonwebtoken'

export type ActorType = 'admin' | 'employee' | 'renter'

export type ActorTokenPayload = jwt.JwtPayload & {
  sub: string
  type: ActorType
  sessionVersion?: number
  last2faAt?: number
}

const ISSUER = 'rentaldrivego-api'
const ALG: jwt.Algorithm[] = ['HS256']

function getJwtSecret() {
  const secret = process.env.JWT_SECRET
  if (!secret) throw new Error('JWT_SECRET is required')
  return secret
}

export function signActorToken(
  actorId: string,
  actorType: ActorType,
  options: Pick<jwt.SignOptions, 'expiresIn'> & { sessionVersion?: number; last2faAt?: number } = {},
) {
  const { sessionVersion, last2faAt, ...signOptions } = options
  return jwt.sign(
    {
      sub: actorId,
      type: actorType,
      ...(sessionVersion === undefined ? {} : { sessionVersion }),
      ...(last2faAt === undefined ? {} : { last2faAt }),
    },
    getJwtSecret(),
    {
      algorithm: 'HS256',
      issuer: ISSUER,
      audience: actorType,
      expiresIn: signOptions.expiresIn ?? '8h',
    },
  )
}

export function verifyActorToken(token: string, expectedType: ActorType): ActorTokenPayload {
  const payload = jwt.verify(token, getJwtSecret(), {
    algorithms: ALG,
    issuer: ISSUER,
    audience: expectedType,
  }) as jwt.JwtPayload

  if (typeof payload.sub !== 'string' || payload.type !== expectedType) {
    throw new Error('Invalid actor token')
  }

  return payload as ActorTokenPayload
}

export function verifyAnyActorToken(token: string): ActorTokenPayload {
  const decoded = jwt.decode(token) as jwt.JwtPayload | null
  const actorType = decoded?.type

  if (actorType !== 'admin' && actorType !== 'employee' && actorType !== 'renter') {
    throw new Error('Invalid actor token')
  }

  return verifyActorToken(token, actorType)
}
