import Keycloak from 'keycloak-js'
import { getEnv } from '~/modules/__env'
import { keycloakAuthCache } from '~/utils/keycloakAuthCache'
import { getResolvedKeycloakUrl } from '~/utils/keycloakUrl'

declare global {
    interface Window {
        __KEYCLOAK_INITIALIZED_PROMISE__?: Promise<boolean>
        __KEYCLOAK_INSTANCE__?: Keycloak
    }
}

export const KEYCLOAK_URL = getResolvedKeycloakUrl()

// Memoized config - computed once
const keycloakConfig = (() => {
    const env = getEnv()
    return {
        url: KEYCLOAK_URL,
        realm: env.DEFAULT_REALM,
        clientId: env.DEFAULT_CLIENT_ID,
    }
})()

window.__KEYCLOAK_INSTANCE__ = new Keycloak(keycloakConfig)

export const checkIfAuthenticated = async (overrideExisting = false) => {
    if (window.__KEYCLOAK_INSTANCE__!.authenticated) {
        return true
    }

    if (overrideExisting || !window.__KEYCLOAK_INSTANCE__) {
        // Create a completely new instance to ensure proper state
        window.__KEYCLOAK_INSTANCE__ = new Keycloak(keycloakConfig)
    }

    // for chrome extension, we need to always initialize keycloak
    if (!window.__KEYCLOAK_INITIALIZED_PROMISE__ || overrideExisting) {
        const cachedTokens = overrideExisting ? null : keycloakAuthCache.load()
        window.__KEYCLOAK_INITIALIZED_PROMISE__ = new Promise(
            (resolve, reject) => {
                window
                    .__KEYCLOAK_INSTANCE__!.init({
                        pkceMethod: 'S256',
                        onLoad: cachedTokens ? 'login-required' : 'check-sso',
                        checkLoginIframe: cachedTokens ? false : true,
                        silentCheckSsoRedirectUri: cachedTokens
                            ? undefined
                            : `${window.location.origin}/check-sso.html`,
                        ...(cachedTokens && {
                            token: cachedTokens?.token,
                            refreshToken: cachedTokens?.refreshToken,
                            idToken: cachedTokens?.idToken,
                            timeSkew: cachedTokens?.timeSkew,
                        }),
                    })
                    .then(async (authenticated: boolean) => {
                        if (!authenticated) {
                            keycloakAuthCache.clear()
                            resolve(false)
                            return
                        }

                        // Check if token is expired and refresh it
                        if (window.__KEYCLOAK_INSTANCE__!.isTokenExpired(60)) {
                            // Check if expires in < 60s
                            try {
                                const refreshed =
                                    await window.__KEYCLOAK_INSTANCE__!.updateToken(
                                        60
                                    )
                                if (refreshed) {
                                    keycloakAuthCache.save(
                                        window.__KEYCLOAK_INSTANCE__!
                                    ) // Save new token
                                }
                            } catch (error) {
                                keycloakAuthCache.clear()
                                resolve(false)
                                return
                            }
                        }

                        keycloakAuthCache.save(window.__KEYCLOAK_INSTANCE__!)
                        resolve(true)
                    })
                    .catch((error) => {
                        keycloakAuthCache.clear()
                        window.__KEYCLOAK_INITIALIZED_PROMISE__ = undefined
                        reject(error)
                    })
            }
        )
    }

    return window.__KEYCLOAK_INITIALIZED_PROMISE__
}

export const keycloakInstance = new Proxy({} as Keycloak, {
    get(_target, prop) {
        return window.__KEYCLOAK_INSTANCE__![prop]
    },
    set(_target, prop, value) {
        window.__KEYCLOAK_INSTANCE__![prop] = value
        return true
    },
})
