<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { cssAssetUrl } from '@/commons/assets.ts'
import MobileStage from '@/components/MobileStage.vue'
import { useGameSocket, sendGameMessage, userJoinStatus, userTop10RankStatus, joinSharedRoom } from '@/composables/useGameSocket'
import LoadingView from './views/LoadingView.vue'
import PlayingView from './views/PlayingView.vue'
import ScoreView from './views/ScoreView.vue'
import { $alreadyRankedToast, $getWechat, $toast } from '@/commons/utils.ts'
import { playGame1Music, stopAllMusic } from '@/commons/music'

type GameView = 'loading' | 'playing' | 'score'

const imageUrls = {
    bg: cssAssetUrl('game1/bg.png'),
    bg2: cssAssetUrl('game1/bg2.png'),
    logo: cssAssetUrl('logo.png'),
    title: cssAssetUrl('game1/title.png'),
    avatar: cssAssetUrl('avatar-yellow.png'),
    gu: cssAssetUrl('game1/gu.png'),
    clock: cssAssetUrl('game1/clock.png'),
    guSprite: cssAssetUrl('game1/gu-sprite.png'),
    scoreBg: cssAssetUrl('game1/score-bg.png'),
    back: cssAssetUrl('game1/back.png'),
    replay: cssAssetUrl('game1/replay.png'),
    close: cssAssetUrl('game1/close.png'),

    rule: cssAssetUrl('game1/rule.png')
}

const wechat = $getWechat()
const currentView = ref<GameView>('loading')
const countdownInterval = ref(60)
const isDivDescVisible = ref(false)
const isGameEnded = ref(false)
const tick = ref(0)  //点击次数
const rank = ref(0)  //排名
const roomStatus = ref(0)
const hasFinalScoreResult = ref(false)
const currentGuFrame = ref(0)
const isGuPlaying = ref(false)
const token = ref(wechat?.token ?? '')
const nickname = ref(wechat?.nickname ?? '')
const avatar = ref(wechat?.avatar ?? '')
const showGameRule = ref(true)

const mobileStageRef = ref<InstanceType<typeof MobileStage> | null>(null)
const _offSocketMessage = ref<(() => void) | undefined>()
let guFrameTimer: ReturnType<typeof window.setTimeout> | undefined
let gameCountdownTimer: ReturnType<typeof window.setTimeout> | undefined

const confirmRefresh = (event: BeforeUnloadEvent) => {
    event.preventDefault()
    event.returnValue = ''
}

function getServerRank(data: any, fallback?: unknown) {
    const value = typeof data === 'object' && data
        ? data.rank ?? data.rank_no ?? data.rankNo ?? data.game_rank ?? data.gameRank ?? fallback
        : data
    const nextRank = Number(value)
    return Number.isFinite(nextRank) && nextRank > 0 ? nextRank : 0
}


function showFinalScoreIfReady() {
    if (roomStatus.value !== 4 || !hasFinalScoreResult.value) return
    hasFinalScoreResult.value = false
    showScoreView()
}

function markFinalScoreResult() {
    hasFinalScoreResult.value = true
    showFinalScoreIfReady()
}

function syncFinalStatus(data: any) {
    const nextStatus = Number(data?.status)
    if (!Number.isFinite(nextStatus)) return

    roomStatus.value = nextStatus
    if (nextStatus === 3) {
        return
    }
    if (nextStatus !== 4) return

    const nextRank = getServerRank(data)
    const nextScore = Number(data?.score)
    if (nextRank > 0) {
        rank.value = nextRank
    }
    if (Number.isFinite(nextScore) && nextScore >= 0) {
        tick.value = nextScore
    }
    showFinalScoreIfReady()
}

function setDivDescVisible(visible: boolean) {
    isDivDescVisible.value = visible
}

function stopGameCountdown() {
    if (gameCountdownTimer) {
        window.clearTimeout(gameCountdownTimer)
        gameCountdownTimer = undefined
    }
}

function submitScore(save: boolean = false, currentTick = tick.value) {
    //最后提交保存在数据库中
    if (save) {
        //item_num 游戏项目(1到6)
        //wechat 原始token
        const sent = sendGameMessage('submit_score_save', {
            score: currentTick,
            wechat: wechat.token,
            item_num: 1,
            nickname: wechat.nickname,
            avatar: wechat.avatar,
            rank: rank.value,
        })
        return sent
    } else {
        return sendGameMessage('submit_score', { score: currentTick })
    }
}

function startGameCountdown(seconds = 60) {
    stopGameCountdown()
    countdownInterval.value = seconds
    setDivDescVisible(true)

    const tickCountdown = () => {
        countdownInterval.value -= 1

        if (countdownInterval.value <= 0) {
            countdownInterval.value = 0
            gameCountdownTimer = undefined
            setDivDescVisible(false)
            isGameEnded.value = true
            hasFinalScoreResult.value = false
            const sent = submitScore(true)
            if (userTop10RankStatus.value) {
                userJoinStatus.value = false
                $alreadyRankedToast()
            } else if (sent) {
                $toast('成绩提交中，请稍候...', 5000)
            }
            return
        }

        gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
    }

    gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
}

function syncGameCountdown(seconds: number) {
    const syncedSeconds = Math.max(0, Math.floor(seconds))
    if (countdownInterval.value - syncedSeconds <= 1) return

    if (syncedSeconds === 0) {
        countdownInterval.value = 0
        return
    }

    startGameCountdown(syncedSeconds)
}

function resetToLoadingView() {
    stopGameCountdown()
    if (guFrameTimer) {
        window.clearTimeout(guFrameTimer)
        guFrameTimer = undefined
    }
    tick.value = 0
    rank.value = 0
    roomStatus.value = 0
    hasFinalScoreResult.value = false
    countdownInterval.value = 60
    currentGuFrame.value = 0
    isGuPlaying.value = false
    userJoinStatus.value = false
    currentView.value = 'loading'
    setDivDescVisible(false)
}

function startGameView() {
    stopGameCountdown()
    tick.value = 0
    currentGuFrame.value = 0
    roomStatus.value = 2
    hasFinalScoreResult.value = false
    isGameEnded.value = false
    currentView.value = 'playing'
    startGameCountdown()
}

function showScoreView() {
    showGameRule.value = false;
    stopGameCountdown()
    setDivDescVisible(false)
    if (userTop10RankStatus.value) {
        currentView.value = 'loading'
        userJoinStatus.value = false;
        $alreadyRankedToast()
    } else {
        currentView.value = 'score'
    }
}

const touchHandler = () => {
    if (isGuPlaying.value) {
        return
    }

    const nextTick = tick.value + 5
    if (!submitScore(false, nextTick)) return
    tick.value = nextTick
    playGame1Music();
    isGuPlaying.value = true

    let frameIndex = 0
    const playNextFrame = () => {
        currentGuFrame.value = frameIndex
        frameIndex += 1

        if (frameIndex >= 3) {
            guFrameTimer = window.setTimeout(() => {
                currentGuFrame.value = 0
                isGuPlaying.value = false
                guFrameTimer = undefined
            }, 200)
            return
        }

        guFrameTimer = window.setTimeout(playNextFrame, 200)
    }

    playNextFrame()
}

if (wechat) {
    const gameId = 'game1';
    const { offSocketMessage } = useGameSocket({
        gameId,
        auth: {
            userid: wechat.token,
        },
        onConnect: () => {
            window.setTimeout(() => {
                const joined = joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
            }, 200)
        },
        onShowRank: (data) => {
            //第一个游戏没有排行榜,只显示结果
            showScoreView();
        },
        onGameStart: async () => {
            showGameRule.value = false;
            await mobileStageRef.value?.startCountdown()
            startGameView()
        },
        onScoreSubmitted: (is_save, data) => {
            if (!is_save) {//非保存状态下
                const nextScore = Number(typeof data === 'object' ? data?.score : NaN)
                const nextRank = getServerRank(data)
                const remainingSeconds = Number(typeof data === 'object' ? data?.remainingSeconds : NaN)
                if (Number.isFinite(nextScore) && nextScore >= 0) {
                    tick.value = nextScore
                }
                if (nextRank > 0) {
                    rank.value = nextRank
                }
                if (Number.isFinite(remainingSeconds) && remainingSeconds >= 0) {
                    syncGameCountdown(remainingSeconds)
                }
            } else if (typeof data === 'object' && data) {
                const nextRank = getServerRank(data)
                if (nextRank > 0) {
                    rank.value = nextRank
                }
                markFinalScoreResult()
            }
            return { code: 'JGQF', score: tick.value, rank_no: rank.value }
        },
        onStatus: syncFinalStatus,
        onRescoreSubmitted: (_recount) => {
            submitScore(true)
        },
        onGameRecover: (data) => {
            const recoveredRank = getServerRank(data)
            const recoveredScore = Number(data?.score)
            const recoveredSeconds = Number(data?.remainingSeconds)

            rank.value = recoveredRank
            tick.value = Number.isFinite(recoveredScore) && recoveredScore > 0 ? recoveredScore : 0
            showGameRule.value = false
            // showGameRank.value = false
            roomStatus.value = 2
    isGameEnded.value = false
    hasFinalScoreResult.value = false
    currentView.value = 'playing'
            startGameCountdown(
                Number.isFinite(recoveredSeconds) && recoveredSeconds > 0 ? recoveredSeconds : 0,
            )
        },
        onRoomClosed: () => {
            stopGameCountdown()
            currentView.value = 'loading'
            setDivDescVisible(false)
            // alert('管理员关闭了游戏房间')
            $toast('管理员关闭了游戏房间')
        },
        onRoomBack: () => {
        },
    })
    _offSocketMessage.value = offSocketMessage
}

onMounted(() => {
    document.title = '互动游戏 - 击鼓齐福'
    if (token.value) {
        window.addEventListener('beforeunload', confirmRefresh)
    }
})

onBeforeUnmount(() => {
    _offSocketMessage.value?.()
    if (guFrameTimer) {
        window.clearTimeout(guFrameTimer)
    }
    stopGameCountdown()
    stopAllMusic();
    if (token.value) {
        window.removeEventListener('beforeunload', confirmRefresh)
    }
})

const showGameRuleHandler = () => {
    showGameRule.value = !showGameRule.value;
}
</script>

<template>
    <MobileStage v-if="token" :showGameRule="showGameRule" ref="mobileStageRef"
        :background="`${imageUrls.bg} center/cover`">
        <template #gameRule>
            <div class="rule-container">
                <div class="rule-txt-container">
                    <div class="rule-title">游戏规则</div>
                    <div class="rule-txt">
                        1.主持人开赛即可点击鼓面，单次点击得 5 分;<br />
                        2.限时比拼手速，结束后按积分排名;<br />
                        3.高分用户有机会领取新疆福彩定制周边;<br />
                        4.禁止外挂，作弊，违规账号取消成绩与领奖资格;<br /><br />
                        祝您游戏愉快！
                    </div>
                    <div class="rule-close" @click="showGameRuleHandler"></div>
                </div>
            </div>
        </template>
        <LoadingView v-if="currentView === 'loading'" :image-urls="imageUrls" :user-join-status="userJoinStatus"
            @touchGameRule="showGameRuleHandler" />
        <PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="tick" :rank="rank"
            :current-gu-frame="currentGuFrame" :countdown-interval="countdownInterval"
            :is-div-desc-visible="isDivDescVisible" :is-game-ended="isGameEnded" @touch="touchHandler" :userTop10RankStatus="userTop10RankStatus" />
        <ScoreView v-else :image-urls="imageUrls" :rank="rank" :tick="tick" />
    </MobileStage>
    <div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;">
        请使用微信扫码进入游戏
    </div>
</template>
<style scoped>
.rule-container {
    .rule-txt-container {
        background: v-bind('imageUrls.rule') center / cover no-repeat;
        width: 692px;
        height: 797px;
        margin-top: -20%;
        transform: scale(0.5);

        .rule-title {
            text-align: center;
            color: white;
            font-weight: bold;
            font-size: 26pt;
            line-height: 50pt;
            letter-spacing: 4px;
        }

        .rule-txt {
            font-size: 26pt;
            padding: 40px;
            margin-top: 10px;
            color: #AA0000;
        }
    }

    .rule-close {
        width: 57px;
        height: 57px;
        background: v-bind('imageUrls.close') center / cover no-repeat;
        transform: translateX(-50%) scale(1.5);
        position: absolute;
        top: -73px;
        left: 100%;
        margin-left: -48px;
    }
}
</style>
