import { getAuthDetails } from './api'
import type { AllauthResponse, AuthenticationMethod } from './types'

export const AuthChangeEvent = {
    LOGGED_OUT: 'LOGGED_OUT',
    LOGGED_IN: 'LOGGED_IN',
    REAUTHENTICATED: 'REAUTHENTICATED',
    REAUTHENTICATION_REQUIRED: 'REAUTHENTICATION_REQUIRED',
    FLOW_UPDATED: 'FLOW_UPDATED'
}

export default function getAuthChangeEvent(fromAuth: AllauthResponse, toAuth: AllauthResponse): string {
    let before = getAuthDetails(fromAuth)
    const after = getAuthDetails(toAuth)

    if (toAuth.status === 410) {
        return AuthChangeEvent.LOGGED_OUT
    }

    const shouldReauth = () => {
        const fromMethods = (fromAuth.data?.methods as AuthenticationMethod[] | undefined) ?? []
        const toMethods = (toAuth.data?.methods as AuthenticationMethod[] | undefined) ?? []
        return (before.requiresReauthentication) || (fromMethods.length < toMethods.length)
    }

    // Corner case: user ID change. Treat as if we're transitioning from anonymous state.
    if (before.user && after.user && before.user?.id !== after.user?.id) {
        before = { isAuthenticated: false, requiresReauthentication: false, user: null, pendingFlow: undefined }
    }

    if (!before.isAuthenticated && after.isAuthenticated) {
        return AuthChangeEvent.LOGGED_IN
    } else if (before.isAuthenticated && !after.isAuthenticated) {
        return AuthChangeEvent.LOGGED_OUT
    } else if (before.isAuthenticated && after.isAuthenticated) {
        if (after.requiresReauthentication) {
            return AuthChangeEvent.REAUTHENTICATION_REQUIRED
        } else if (shouldReauth()) {
            return AuthChangeEvent.REAUTHENTICATED
        }
    } else if (!before.isAuthenticated && !after.isAuthenticated) {
        const fromFlow = before.pendingFlow
        const toFlow = after.pendingFlow
        if (toFlow?.id && fromFlow?.id !== toFlow.id) {
            return AuthChangeEvent.FLOW_UPDATED
        }
    }

    // No change.
    return ''
}
