import {useQuery, useQueryClient} from '@tanstack/react-query'
import {type PropsWithChildren, useEffect, useRef, useState} from 'react'

import {login, validateToken} from '@/api/auth.ts'
import {userAssets} from '@/api/user.ts'
import {useTranslation} from 'react-i18next'
import {normalizeLanguage} from '@/lib/i18n'
import {queryKeys} from '@/lib/queryKeys.ts'
import {useUserStore} from '@/store/user.ts'
import type {HostContextMessage} from '@/types'

const HOST_READY_MESSAGE = 'PLAYX_READY'
const HOST_READY_INTERVAL = 500
const HOST_READY_RETRY_LIMIT = 20
const TEST_BOOTSTRAP_ENABLED = import.meta.env.VITE_BYPASS_IFRAME_CONTEXT === 'true'
const TEST_BOOTSTRAP_USERNAME = '+60777777777'
const TEST_BOOTSTRAP_LANGUAGE = 'zh'

export function AuthGuide({children}: PropsWithChildren) {
    const {t} = useTranslation()
    const queryClient = useQueryClient()
    const [username, setUsername] = useState(TEST_BOOTSTRAP_ENABLED ? TEST_BOOTSTRAP_USERNAME : '')
    const setUserInfo = useUserStore((state) => state.setUserInfo)
    const setAuthInfo = useUserStore((state) => state.setAuthInfo)
    const setAssetsInfo = useUserStore((state) => state.setAssetsInfo)
    const setLanguage = useUserStore((state) => state.setLanguage)
    const clearUserInfo = useUserStore((state) => state.clearUserInfo)
    const hasHostContextRef = useRef(false)
    const activeUsernameRef = useRef('')

    useEffect(() => {
        if (TEST_BOOTSTRAP_ENABLED) {
            hasHostContextRef.current = true
            activeUsernameRef.current = TEST_BOOTSTRAP_USERNAME
            setLanguage(TEST_BOOTSTRAP_LANGUAGE)
            return
        }

        const isEmbedded = window.parent !== window

        const notifyParentReady = () => {
            if (!isEmbedded || hasHostContextRef.current) {
                return
            }

            window.parent.postMessage({type: HOST_READY_MESSAGE}, '*')
        }

        const handleMessage = (event: MessageEvent<HostContextMessage>) => {
            if (isEmbedded && event.source !== window.parent) {
                return
            }

            const message = event.data

            if (!message || message.type !== 'IFRAME_CONTEXT' || !message.payload) {
                return
            }

            const {language, username: nextUsername} = message.payload

            if (typeof nextUsername === 'string' && nextUsername.trim()) {
                const normalizedUsername = nextUsername.trim()
                if (activeUsernameRef.current && activeUsernameRef.current !== normalizedUsername) {
                    clearUserInfo()
                    queryClient.removeQueries({queryKey: ['auth-bootstrap']})
                }
                hasHostContextRef.current = true
                activeUsernameRef.current = normalizedUsername
                setUsername(normalizedUsername)
            }

            if (typeof language === 'string' && language.trim()) {
                setLanguage(normalizeLanguage(language))
            }
        }

        window.addEventListener('message', handleMessage)

        notifyParentReady()

        const retryTimer = isEmbedded
            ? window.setInterval(() => {
                notifyParentReady()
            }, HOST_READY_INTERVAL)
            : null
        const stopRetryTimer = isEmbedded
            ? window.setTimeout(() => {
                if (retryTimer != null) {
                    window.clearInterval(retryTimer)
                }
            }, HOST_READY_INTERVAL * HOST_READY_RETRY_LIMIT)
            : null

        return () => {
            window.removeEventListener('message', handleMessage)
            if (retryTimer != null) {
                window.clearInterval(retryTimer)
            }
            if (stopRetryTimer != null) {
                window.clearTimeout(stopRetryTimer)
            }
        }
    }, [clearUserInfo, queryClient, setLanguage])

    const authBootstrapQuery = useQuery({
        queryKey: queryKeys.authBootstrap(username),
        enabled: Boolean(username),
        queryFn: async () => {
            const loginResponse = await login({username})
            const userInfo = loginResponse.data.userInfo
            const validateResponse = await validateToken(userInfo.token)
            const authInfo = validateResponse.data
            const assetsResponse = await userAssets({
                session_id: authInfo.session_id,
            })

            return {
                userInfo,
                authInfo,
                assetsInfo: assetsResponse.data,
            }
        },
    })

    useEffect(() => {
        if (!authBootstrapQuery.data) {
            return
        }

        setUserInfo(authBootstrapQuery.data.userInfo)
        setAuthInfo(authBootstrapQuery.data.authInfo)
        setAssetsInfo(authBootstrapQuery.data.assetsInfo)
        queryClient.setQueryData(queryKeys.assets(authBootstrapQuery.data.authInfo.session_id), authBootstrapQuery.data.assetsInfo)
    }, [authBootstrapQuery.data, queryClient, setAssetsInfo, setAuthInfo, setUserInfo])

    useEffect(() => {
        if (!authBootstrapQuery.isError) {
            return
        }

        clearUserInfo()
    }, [authBootstrapQuery.isError, clearUserInfo])

    if (!username || authBootstrapQuery.isPending) {
        return (
            <div className="flex min-h-screen items-center justify-center bg-[#08070E] px-6 text-center text-[14px] text-white/68">
                {!username && !TEST_BOOTSTRAP_ENABLED ? t('auth.waitingForHostContext') : t('auth.loadingAccountData')}
            </div>
        )
    }

    if (authBootstrapQuery.isError) {
        return (
            <div className="flex min-h-screen items-center justify-center bg-[#08070E] px-6 text-center">
                <div className="max-w-[420px] rounded-[14px] border border-white/10 bg-white/4 px-[18px] py-[16px]">
                    <div className="text-[16px] font-semibold text-white">{t('auth.authenticationFailed')}</div>
                    <div className="mt-[8px] text-[13px] leading-[1.6] text-white/58">{t('auth.refreshAndTryAgain')}</div>
                </div>
            </div>
        )
    }

    return <>{children}</>
}
