/**
 * Custom OAuth Provider for Authentik
 *
 * Este archivo extiende nuxt-auth-utils para soportar Authentik como provider OAuth
 */
import type { H3Event } from 'h3'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { useRuntimeConfig } from '#imports'

export interface OAuthAuthentikConfig {
  /**
   * Authentik OAuth Client ID
   * @default process.env.NUXT_OAUTH_AUTHENTIK_CLIENT_ID
   */
  clientId?: string
  /**
   * Authentik OAuth Client Secret
   * @default process.env.NUXT_OAUTH_AUTHENTIK_CLIENT_SECRET
   */
  clientSecret?: string
  /**
   * Authentik Server URL
   * @default process.env.NUXT_OAUTH_AUTHENTIK_SERVER_URL
   */
  serverUrl?: string
  /**
   * Redirect URL
   * @default process.env.NUXT_OAUTH_AUTHENTIK_REDIRECT_URL
   */
  redirectURL?: string
  /**
   * Require email from user, adds the ['email'] scope if not present
   * @default false
   */
  emailRequired?: boolean
  /**
   * Authentik OAuth Scope
   * @default ['openid', 'profile', 'email']
   */
  scope?: string[]
}

export function oauthAuthentikEventHandler({
  config,
  onSuccess,
  onError,
}: {
  config?: OAuthAuthentikConfig
  onSuccess: (event: H3Event, result: { user: any; tokens: any }) => Promise<void> | void
  onError?: (event: H3Event, error: any) => Promise<void> | void
}) {
  return eventHandler(async (event: H3Event) => {
    const runtimeConfig = useRuntimeConfig(event)

    // Debug: Log configuration
    console.log('OAuth Authentik Config:', {
      clientId: runtimeConfig.oauth.authentik.clientId ? '***' : 'MISSING',
      clientSecret: runtimeConfig.oauth.authentik.clientSecret ? '***' : 'MISSING',
      serverUrl: runtimeConfig.oauth.authentik.serverUrl,
      redirectURL: runtimeConfig.oauth.authentik.redirectURL,
    })

    // Merge config with defaults
    const authentikConfig = defu(config, {
      clientId: runtimeConfig.oauth.authentik.clientId,
      clientSecret: runtimeConfig.oauth.authentik.clientSecret,
      serverUrl: runtimeConfig.oauth.authentik.serverUrl,
      redirectURL: runtimeConfig.oauth.authentik.redirectURL,
      scope: ['openid', 'profile', 'email'],
      emailRequired: false
    }) as Required<OAuthAuthentikConfig>

    const query = getQuery(event)

    // Handle callback
    if (query.code) {
      try {
        // Exchange code for tokens
        const tokenUrl = `${authentikConfig.serverUrl}/application/o/token/`
        const tokenResponse = await $fetch(tokenUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
          },
          body: new URLSearchParams({
            grant_type: 'authorization_code',
            client_id: authentikConfig.clientId,
            client_secret: authentikConfig.clientSecret,
            code: query.code as string,
            redirect_uri: authentikConfig.redirectURL,
          }),
        })

        const tokens = tokenResponse as any

        // Get user info
        const userInfoUrl = `${authentikConfig.serverUrl}/application/o/userinfo/`
        const user = await $fetch(userInfoUrl, {
          headers: {
            Authorization: `Bearer ${tokens.access_token}`,
          },
        })

        return onSuccess(event, { user, tokens })
      } catch (error: any) {
        if (onError) return onError(event, error)
        throw error
      }
    }

    // Initial redirect to Authentik
    const authorizationUrl = withQuery(
      `${authentikConfig.serverUrl}/application/o/authorize/`,
      {
        client_id: authentikConfig.clientId,
        redirect_uri: authentikConfig.redirectURL,
        response_type: 'code',
        scope: authentikConfig.scope.join(' '),
      }
    )

    return sendRedirect(event, authorizationUrl)
  })
}

// Export for use in defineOAuthAuthentikEventHandler
export const oauth = {
  authentikEventHandler: oauthAuthentikEventHandler
}
