<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import Loading from './views/LoadingView.vue'
import Rank1 from './views/Rank1View.vue'
import Rank2 from './views/Rank2View.vue'
import { useAdminGameSocket } from '@/composables/useAdminGameSocket'
import type Player from '@/commons/player.ts'
import { playApplauseMusic, playGame1Music, stopAllMusic, stopGame1Music } from '@/commons/music'
import { $confirm, $remove_socket_storage, $toast } from '@/commons/utils.ts'

const router = useRouter()

type GameScreen = 'loading' | 'rank1' | 'rank2'

const PLAYER_LIMIT = 20
const RANK_LIMIT = 10

const emptyLoadingPlayer = () => ({
    score: '-',
    telephone: '',
    userid: '',
    wechat_id: '',
    nickname: '虚位以待',
    avatar: '',
})

const emptyRankPlayer = (index: number): Player => ({
    wechat_id: `empty-${index}`,
    nickname: '虚位以待',
    avatar: '',
    score: '-',
})

const screen = ref<GameScreen>('loading')
const loadingPlayers = ref<any[]>(Array.from({ length: PLAYER_LIMIT }, emptyLoadingPlayer))
const playerCount = ref(0)
const rankPlayers = ref<Player[]>(Array.from({ length: RANK_LIMIT }, (_, index) => emptyRankPlayer(index)))
const rank1Ref = ref<InstanceType<typeof Rank1> | null>(null)
let isPlayingStartAnimation = false

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

const renderPlayers = (data: any) => {
    const players = Array.isArray(data?.list) ? data.list : []
    playerCount.value = Number(data?.count ?? players.length)
    loadingPlayers.value = Array.from(
        { length: PLAYER_LIMIT },
        (_, index) => players[index] ?? emptyLoadingPlayer(),
    )
}

const updateRankPlayers = (data: any) => {
    if (!Array.isArray(data)) return

    rankPlayers.value = Array.from(
        { length: RANK_LIMIT },
        (_, index) => data[index] ?? emptyRankPlayer(index),
    )
}

const playerToRankPlayer = (player: any, index: number): Player => ({
    telephone: player?.telephone ?? '',
    userid: player?.userid ?? '',
    wechat_id: player?.wechat_id || `empty-${index}`,
    nickname: player?.nickname || '虚位以待',
    avatar: player?.avatar || '',
    score: player?.score ?? '-',
})

const seedRankPlayersFromLoading = () => {
    rankPlayers.value = Array.from(
        { length: RANK_LIMIT },
        (_, index) => {
            const player = loadingPlayers.value[index]

            if (!player?.userid && !player?.wechat_id) {
                return emptyRankPlayer(index)
            }

            return playerToRankPlayer(player, index)
        },
    )
}

const resetRoundState = () => {
    playerCount.value = 0
    loadingPlayers.value = Array.from({ length: PLAYER_LIMIT }, emptyLoadingPlayer)
    rankPlayers.value = Array.from({ length: RANK_LIMIT }, (_, index) => emptyRankPlayer(index))
    isPlayingStartAnimation = false
}

const gotoLoading = (reset = false) => {
    if (reset) {
        resetRoundState()
    }

    screen.value = 'loading'
}

const gotoRank1WithIntro = async () => {
    if (isPlayingStartAnimation) return

    isPlayingStartAnimation = true
    seedRankPlayersFromLoading()
    screen.value = 'rank1'
    await nextTick()
    await rank1Ref.value?.startIntro()
    screen.value = 'rank2'
    isPlayingStartAnimation = false
}

const gameId = 'game1'
const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
    gameId,
    onRoomState: (data: any) => {
        if (Array.isArray(data?.list)) {
            renderPlayers(data)
        }
        switch (data?.status) {
            case 0:
                gotoLoading(true)
                createRoom(1)
                break
            case 1:
                // if(data.gameId && data.gameId!=gameId){
                //     return;
                // }
                gotoLoading()
                break
            case 2:
                seedRankPlayersFromLoading()
                screen.value = 'rank1'
                break
            case 3:
                screen.value = 'rank2'
                break
        }
    },
    onRoomJoin: (data) => {
        renderPlayers(data)
        gotoLoading()
    },
    onGameStart: gotoRank1WithIntro,
    onRoomRank: updateRankPlayers,
    onRelogin: async () => {
        $remove_socket_storage();
        await router.replace('/')
    }
})

const startGameWithMusic = () => {
    if (playerCount.value == 0) {
        // alert('房间中没有玩家')
        $toast('房间中没有玩家');
        return;
    }
    startGame()
}

const nextRound = () => {
    gotoLoading(true)
    //重开房间
    backRoom(1)
}

const nextRoundWithMusic = () => {
    nextRound()
}

const backHandler = async () => {
    const ok = await $confirm({
        title: '提示',
        message: '是否关闭当前房间回到首页',
        confirmText: '确定',
        cancelText: '取消',
    })
    if (ok) {
        closeRoom();
        stopAllMusic()
        router.replace('/main');
    }
}

onMounted(() => {
    window.addEventListener('beforeunload', confirmRefresh)
    playGame1Music()
})

onUnmounted(() => {
    stopAllMusic()
    window.removeEventListener('beforeunload', confirmRefresh)
})

watch(screen, (value) => {
    // console.log(value);
    if (value == 'rank2') {
        playApplauseMusic();
    } else if (value == 'loading') {
        playGame1Music();
    }
})
</script>

<template>
    <Loading v-if="screen === 'loading'" :players="loadingPlayers" :player-count="playerCount"
        @start="startGameWithMusic" @back="backHandler" />
    <Rank1 v-else-if="screen === 'rank1'" ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic" />
    <Rank2 v-else :rank-list="rankPlayers" @next="nextRoundWithMusic" @back="backHandler" />
</template>
