<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } 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, $format_str, $getWechat, $toast } from '@/commons/utils.ts'
import { playGame6Music, stopAllMusic } from '@/commons/music';

type GameView = 'loading' | 'playing' | 'score'
type RankPlayer = {
    rank: number
    nickname: string
    avatar: string
    score: number | string
}

const imageUrls: Record<string, string> = {
    avatar: cssAssetUrl('avatar-yellow.png'),
    scoreBg: cssAssetUrl('game1/score-bg.png'),
    bg: cssAssetUrl('game6/bg.png'),
    logo: cssAssetUrl('logo.png'),
    loadingBg1: cssAssetUrl('game6/loadingbg1.png'),
    loadingBg2: cssAssetUrl('game6/loadingbg2.png'),
    close: cssAssetUrl('game1/close.png'),
    clock: cssAssetUrl('game1/clock.png'),
    bg2: cssAssetUrl('game6/bg2.png'),
    hydt: cssAssetUrl('game6/hydt.png'),
    rank: cssAssetUrl('game6/rank.png'),
    moleShowSprite: cssAssetUrl('game6/mole_show.png'),
    moleHideSprite: cssAssetUrl('game6/mole_hide.png'),
    moleHideprite: cssAssetUrl('game6/mole_hit.png'),
    rabbitFaintprite: cssAssetUrl('game6/rabbit_faint.png'),
    rabbitHideprite: cssAssetUrl('game6/rabbit_hide.png'),
    rabbitshowprite: cssAssetUrl('game6/rabbit_show.png'),
    land: cssAssetUrl('game6/land.png'),
    hammer: cssAssetUrl('game6/hammer.png'),
    ranklist: cssAssetUrl('game6/ranklist.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 score = ref(0)
const rank = ref(0)  //排名
const roomStatus = ref(0)
const hasFinalScoreResult = ref(false)
const rankList = ref<RankPlayer[]>([])
const displayRankList = computed<RankPlayer[]>(() => {
    const list = rankList.value.slice(0, 10)

    return Array.from({ length: 10 }, (_, index) => {
        return list[index] ?? {
            rank: index + 1,
            nickname: '-',
            avatar: '',
            score: '-',
        }
    })
})
const rankScore = computed<number | string>(() => {
    const currentPlayer = rankList.value
        .slice(0, 10)
        .find(item => item.rank === rank.value)

    return currentPlayer?.score ?? score.value
})
// const guFrames: [string, string, string] = [imageUrls.gu01, imageUrls.gu02, imageUrls.gu03]
// const currentGu = ref(imageUrls.gu01)
const isGuPlaying = ref(false)
const token = ref(wechat?.token ?? '')
const nickname = ref(wechat?.nickname ?? '')
const avatar = ref(wechat?.avatar ?? '')
const showGameRule = ref(true)
const showGameRank = ref(false)

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
    showGameOverRank()
}

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

    if (Array.isArray(data?.list)) {
        rankList.value = data.list.map((item: any, index: number) => ({
            rank: getServerRank(item, index + 1),
            nickname: String(item?.nickname ?? ''),
            avatar: String(item?.avatar ?? ''),
            score: Number(item?.score ?? 0),
        }))
    }

    const nextRank = getServerRank(data)
    const nextScore = Number(data?.score)
    if (nextRank > 0) {
        rank.value = nextRank
    }
    if (Number.isFinite(nextScore) && nextScore >= 0) {
        score.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 = score.value) {
    //最后提交保存在数据库中
    if (save) {
        //item_num 游戏项目(1到6)
        //wechat 原始token
        const sent = sendGameMessage('submit_score_save', {
            score: currentTick,
            wechat: wechat.token,
            item_num: 6,
            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;
                showGameRank.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
    }
    score.value = 0
    rank.value = 0
    roomStatus.value = 0
    hasFinalScoreResult.value = false
    rankList.value = []
    roomStatus.value = 0
    hasFinalScoreResult.value = false
    countdownInterval.value = 60
    // currentGu.value = guFrames[0]
    isGuPlaying.value = false
    userJoinStatus.value = false
    showGameRank.value = false
    currentView.value = 'loading'
    setDivDescVisible(false)
}

function startGameView() {
    stopGameCountdown()
    score.value = 0
    rank.value = 0
    roomStatus.value = 0
    hasFinalScoreResult.value = false
    rankList.value = []
    roomStatus.value = 0
    hasFinalScoreResult.value = false
    // currentGu.value = guFrames[0]
    showGameRank.value = false
    roomStatus.value = 2
    hasFinalScoreResult.value = false
    isGameEnded.value = false
    currentView.value = 'playing'
    startGameCountdown()
}

function showGameOverRank() {
    stopGameCountdown()
    setDivDescVisible(false)
    currentView.value = 'score'
    showGameRank.value = false
    userJoinStatus.value = false;
}

const touchHandler = (mole: boolean) => {
    let scoreDelta = mole ? 5 : 0;
    let nextTick = score.value + scoreDelta
    if (mole) {
        if (!submitScore(false, nextTick)) return
        score.value = nextTick
        playGame6Music(1);
    } else {
        playGame6Music(2);
    }
}

if (wechat) {
    const gameId = 'game6';
    const { offSocketMessage } = useGameSocket({
        gameId,
        auth: {
            userid: wechat.token,
        },
        onConnect: () => {
            window.setTimeout(() => {
                const joined = joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
            }, 200)
        },
        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) {
                    score.value = nextScore
                }
                if (nextRank > 0) {
                    rank.value = nextRank
                }
                if (Number.isFinite(remainingSeconds) && remainingSeconds >= 0) {
                    syncGameCountdown(remainingSeconds)
                }
            } else if (typeof data === 'object' && data) {
                if (Array.isArray(data.list)) {
                    rankList.value = data.list.map((item: any, index: number) => ({
                        rank: getServerRank(item, index + 1),
                        nickname: String(item?.nickname ?? ''),
                        avatar: String(item?.avatar ?? ''),
                        score: Number(item?.score ?? 0),
                    }))
                }

                const nextRank = getServerRank(data)
                if (nextRank > 0) {
                    rank.value = nextRank
                }
                markFinalScoreResult()
            }
            return { code: 'FYDT', score: score.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
            score.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)
            $toast('管理员关闭了游戏房间')
        },
        onRoomBack: () => {
        },
    })
    _offSocketMessage.value = offSocketMessage
}

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

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

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

const renderBG = () => {
    if (currentView.value == 'playing') {
        return `${imageUrls.bg2} center/cover`
    }
    return `${imageUrls.bg} center/cover`;
}
const rankCloseHandler = () => {
    showGameRank.value = false
}
</script>

<template>
    <MobileStage v-if="token" :showGameRule="showGameRule" :showGameRank="showGameRank" ref="mobileStageRef"
        :background="`${renderBG()}`">
        <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>
        <template #gameRank>
            <div class="ranklist-container">
                <div class="txt-title">排行</div>
                <div class="list-container">
                    <div class="row row-1">
                        <div class="col-1">排名</div>
                        <div class="col-2">用户</div>
                        <div class="col-3">成绩</div>
                    </div>
                    <div class="row-2">
                        <div class="row rank-row" v-for="(item, index) in displayRankList"
                            :key="`${item.rank}-${index}`">
                            <div class="col-1">
                                <div>{{ item.rank }}</div>
                            </div>
                            <div class="col-2">
                                <div class="avatar"
                                    :style="item.avatar ? { backgroundImage: `url(${item.avatar})` } : {}"></div>
                                <div>{{ $format_str(item.nickname, 12) }}</div>
                            </div>
                            <div class="col-3">{{ item.score }}</div>
                        </div>
                    </div>
                    <div class="row row-3">
                        <div class="col-1"></div>
                        <div class="col-2">
                            <div class="avatar" :style="{ backgroundImage: `url(${avatar})` }"></div>
                            <div>{{ nickname }}</div>
                        </div>
                        <div class="col-3">{{ rankScore }}</div>
                    </div>
                </div>
                <div class="img-close" @click="rankCloseHandler"></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="score" :rank="rank" :countdown-interval="countdownInterval"
            :is-div-desc-visible="isDivDescVisible" :is-game-ended="isGameEnded" @touch="touchHandler" />
        <ScoreView v-else :image-urls="imageUrls" :tick="score" :rank="rank" />
    </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;
    }
}

.ranklist-container {
    width: 747px;
    height: 1084px;
    background: v-bind('imageUrls.ranklist');
    transform: translate(-50%, -50%) scale(0.45);
    left: 50%;
    top: 50%;
    position: absolute;

    .txt-title {
        width: 100%;
        text-align: center;
        font-size: 50px;
        margin-top: 35px;
        font-weight: bold;
        color: #AA0000;
        letter-spacing: 2px;
    }

    .list-container {
        width: calc(100% - 90px);
        height: calc(100% - 210px);
        position: absolute;
        left: 40px;
        top: 140px;
        text-align: center;
        height: 73px;
        line-height: 73px;
        font-size: 32px;

        .row {
            display: grid;
            grid-template-columns: 150px auto 150px;
            align-items: center;
        }

        .row-1 {
            color: #AA0000;
            font-weight: bold;
            background: linear-gradient(-84deg, #FFD396 0%, #FFF3D1 53%, #FFD59C 100%);
            border-radius: 20px 20px 0px 0px;
        }

        .row-2 {
            color: #633911;

            .rank-row:nth-child(odd) {
                background: #F2E2AE;
            }

            .rank-row:nth-child(even) {
                background: #FCEEBF;
            }

            .col-1 {
                position: relative;
            }
        }

        .row-3 {
            background: linear-gradient(0deg, #F4B64C 0%, #F7C96F 100%);
            border-radius: 0px 0px 20px 20px;
        }

        .col-2 {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 18px;

            .avatar {
                width: 48px;
                height: 48px;
                flex: 0 0 auto;
                border-radius: 50%;
                background-position: center;
                background-size: cover;
            }
        }
    }
}

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