import { ApiUnauthorizedException } from "@components/api-exceptions"
import bearer from "@elysiajs/bearer"
import Elysia from "elysia"
import { type JWTPayload, createRemoteJWKSet, jwtVerify } from "jose"

export type AuthOptions = {
  certificateUrl: string
}

export type FlowcoreJWTPayload = JWTPayload & {
  flowcore_user_id: string
  email: string
}

export type FlowcoreAuthenticatedUser = {
  id: string
  email: string
}

/**
 * This method is used to create a JWKS guard.
 * @param {AuthOptions} options - The options for JWKS guard creation.
 * @returns The Elysia instance with the JWKS guard.
 * @throws {Error} - If the bearer token is invalid or the JWKS validation fails with a 401 error
 */
export function createJwksGuard(options: AuthOptions) {
  const jwks = createRemoteJWKSet(new URL(options.certificateUrl))

  const guardRoute = new Elysia()
    .use(bearer())
    .derive({ as: "scoped" }, async ({ bearer, set }): Promise<{ flowcoreUser: FlowcoreAuthenticatedUser }> => {
      const token = bearer as string

      const { payload } = await jwtVerify<FlowcoreJWTPayload>(token, jwks, {}).catch(() => ({
        payload: null,
      }))

      if (!payload?.flowcore_user_id) {
        throw new ApiUnauthorizedException()
      }

      return {
        flowcoreUser: {
          id: payload.flowcore_user_id,
          email: payload.email,
        },
      }
    })

  return guardRoute
}
