<script setup lang="ts">
import { computed, onMounted, ref, useTemplateRef, watch, type Ref } from 'vue';
import assets from '../assets';
import AniEle from '../components/AniEle.vue';

const shootNotice = useTemplateRef('shoot-notice');

defineExpose({
    init: () => {
        shootNotice.value?.jumpTo('蓄力');
    }
})


const props = defineProps<{
    userdata: {
        region: string;
        store: string;
        username: string;
    }
}>();

const sunEle = useTemplateRef('sun-ani');
const sunEndEle = useTemplateRef('sun-ani-end');

const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
const emit = defineEmits(['cloudUp', 'cloudDown', 'restart']);

async function shoot() {
    //sunEle.value?.jumpTo('天上飞')
    sunEle.value?.jumpTo('蓄力飞')

    await document.querySelector('.sun-ani-wrapper')?.animate([
        { transform: 'translateY(0) translateX(-50%)' },
        { transform: 'translateY(8%) translateX(-50%)' },
    ], {
        duration: 900,
        easing: 'linear',
        fill: 'forwards',
    }).finished

    document.querySelector('.arrow')?.animate([
        { opacity: 1 },
        { opacity: 0 },
    ], {
        duration: 500,
        easing: 'ease-in',
        fill: 'forwards',
    }).finished.then(() => {
        document.querySelector('.arrow')?.remove();
    });
    emit('cloudUp');
    document.querySelector('.bed')?.animate([
        { transform: 'translateY(0)' },
        { transform: 'translateY(150%)' },
    ], {
        duration: 500,
        delay: 200,
        easing: 'cubic-bezier(0.4, 0, 1, 0.5)',
        fill: 'forwards',
    });

    await document.querySelector('.sun-ani-wrapper')?.animate([
        { transform: 'translateY(8%) translateX(-50%)', width: '60vw' },
        { transform: 'translateY(-180%) translateX(-50%)', width: '50vw' },
    ], {
        duration: 3200,
        easing: 'cubic-bezier(0.99, 0.13, 0.35, 0.74)',
        fill: 'forwards',
    }).finished

    emit('cloudDown');
    await document.querySelector('.sun-ani-wrapper')?.animate([
        { transform: 'translateY(-180%) translateX(-50%)' },
        { transform: 'translateY(-70%) translateX(-50%)' },
    ], {
        duration: 1200,
        easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)',
        fill: 'forwards',
    }).finished

    /* await wait(1000) */
    canAction.value = true;


    gameLoop();

}
const gPos: Ref<'left' | 'center' | 'right'> = ref('center');
const gDeg = computed(() => ({
    left: 294 - 360,
    center: 326 - 360,
    right: 8
})[gPos.value]);

const SPEED = 1.8;
const transitionOn = ref(true);
let lastTime = 0;

const calcGiftDis = () => {
    if (giftPos.value[0] !== null && giftPos.value[1] !== null) {
        const sunX = sunPos.value[0];
        const sunY = sunPos.value[1];
        const giftX = giftPos.value[0];
        const giftY = giftPos.value[1];

        // 计算太阳和礼物之间的距离
        const distance = Math.sqrt(Math.pow(sunX - giftX, 2) + Math.pow(sunY - giftY, 2));
        return distance;
    } else return 0;
}

const collisionThreshold = 10; // vw 单位
const isPlayingDropAni = ref(false);


function gameLoop(currentTime = 0) {
    let pauseFlag = false;
    if (giftShow.value) {
        giftProgress.value++
        giftPos.value = [null, null];
        giftShow.value = false;
        lastTime = currentTime;
        if (giftProgress.value >= giftList.length) {
            // 游戏结束逻辑
            console.log('游戏结束！耗时:', timeSpent.value / 1000, '秒');
            gameEnd()
            return;
        }
    }

    if (lastTime === 0) lastTime = currentTime;
    const deltaTime = currentTime - lastTime;
    lastTime = currentTime;
    timeSpent.value += deltaTime

    // 移动距离 = 速度 * 时间间隔 / 16.67 (目标帧率约60fps)
    if (sunPos.value[1] < -50) {
        transitionOn.value = false;
        if (!isPlayingDropAni.value)
            (async () => {
                isPlayingDropAni.value = true;

                // sunPos.y to -150, than y to 174 and drop to 124
                transitionOn.value = true;
                while (sunPos.value[1] > -150) {
                    // 逐渐加速
                    sunPos.value[1] -= SPEED * (deltaTime / 16.67) * 4;
                    await wait(16.67 / 2);
                }
                sunPos.value[1] = -150;
                // 等待0.5秒

                transitionOn.value = false;
                await wait(500);

                sunPos.value[1] = 124;
                await wait(0);
                transitionOn.value = true;
                while (sunPos.value[1] > 66) {
                    sunPos.value[1] -= SPEED * (deltaTime / 16.67) * 6;
                    await wait(16.67 / 2);
                }
                // 最终位置 y = 66
                sunPos.value[1] = 66;
                isPlayingDropAni.value = false;

            })();

    } else if (!isPlayingDropAni.value) {
        transitionOn.value = true;
        sunPos.value[1] -= SPEED * 0.3 * (deltaTime / 16.67);
    }


    const moveGift = () => {
        if (giftPos.value[0] === null) {
            // 一直生成礼物，直到距离大于 collisionThreshold * 1.5
            while (true) {
                // 生成起始点
                giftStartPos.value[0] = Math.random() * 60 - 30;
                giftStartPos.value[1] = Math.random() * 80 - 20;

                // 生成终点
                giftEndPos.value[0] = Math.random() * 60 - 30;
                giftEndPos.value[1] = Math.random() * 80 - 20;

                // 初始位置为起始点
                giftPos.value[0] = giftStartPos.value[0];
                giftPos.value[1] = giftStartPos.value[1];

                // 重置移动进度和方向
                giftMoveProgress.value = 0;
                giftMoveDirection.value = 1;

                if (calcGiftDis() > collisionThreshold * 1.5) {
                    break; // 距离足够远，退出循环
                }
            }
        }

        // gift move between two points
        if (giftPos.value[0] !== null && giftPos.value[1] !== null) {
            const giftSpeed = 0.8 * (deltaTime / 16.67); // 速度加快 (原来是0.3)

            // 更新移动进度
            giftMoveProgress.value += giftSpeed * giftMoveDirection.value * 0.01;

            // 检查是否到达端点，如果是则反转方向
            if (giftMoveProgress.value >= 1) {
                giftMoveProgress.value = 1;
                giftMoveDirection.value = -1;
            } else if (giftMoveProgress.value <= 0) {
                giftMoveProgress.value = 0;
                giftMoveDirection.value = 1;
            }

            // 使用线性插值计算当前位置
            giftPos.value[0] = giftStartPos.value[0] + (giftEndPos.value[0] - giftStartPos.value[0]) * giftMoveProgress.value;
            giftPos.value[1] = giftStartPos.value[1] + (giftEndPos.value[1] - giftStartPos.value[1]) * giftMoveProgress.value;
        }

    }

    moveGift();

    // 计算太阳和礼物之间的距离
    const distance = calcGiftDis()
    // 碰撞检测阈值（可以根据实际元素大小调整）
    if (distance < collisionThreshold) {
        // 太阳和礼物碰撞了
        console.log('太阳收集到礼物！', { sunPos: sunPos.value, giftPos: giftPos.value, distance });

        pauseFlag = true; // 暂停游戏循环
        giftShow.value = true; // 显示展示礼物界面
        document.querySelector('.gift-item.show')?.animate([
            { transform: 'scale(1)' },
            { transform: 'scale(0)' },
        ], {
            duration: 900,
            easing: 'cubic-bezier(0.42,-0.98, 0.4, 1)',
            fill: 'forwards',
        }).finished.then(() => {
            giftPos.value = [null, null]; // 重置游戏中礼物
        });
    }


    if (!pauseFlag) requestAnimationFrame(gameLoop);
}

function gToggle(pos: 'left' | 'center' | 'right') {
    gPos.value = pos;
    document.querySelector('.p-machine')?.animate([
        { scale: 1, },
        { scale: 1.2, },
        { scale: 1, },
    ], {
        duration: 200,
        easing: 'ease-in-out',
        fill: 'forwards',
    });

    if (isPlayingDropAni.value) {
        // 如果正在下落动画中，直接返回
        return;
    }

    if (sunPos.value[0] < -36
        || sunPos.value[0] > 36
        || sunPos.value[1] > 70) {
        // 太阳位置不在范围内，直接返回
        return;
    }

    const windAniMap: Record<'left' | 'center' | 'right', [number, [number, number], [number, number]]> = {
        left: [
            -60,
            [70, 0],
            [0, -60],
        ],
        center: [
            -30,
            [0, 0],
            [0, -60],
        ],
        right: [
            0,
            [-70, 0],
            [30, -60],
        ],
    };
    const windAni = windAniMap[pos];

    const windEl = document.querySelector('.wind') as HTMLElement | null;
    if (windEl) {
        windEl.style.rotate = `${windAni[0]}deg`;
    }

    windEl?.animate([
        { left: windAni[1][0] + 'vw', top: windAni[1][1] + 'vw', opacity: 0 },
        { opacity: 1 },
        { left: windAni[2][0] + 'vw', top: windAni[2][1] + 'vw', opacity: 0 },
    ], {
        duration: 500,
        easing: 'ease-in-out',
        fill: 'forwards',
    });
    ({
        'left': [-2, 4],
        'center': [0, 6],
        'right': [2, 4],
    })[pos].forEach((v, i) => {
        sunPos.value[i] += v * SPEED * 2;
    });

    if (sunPos.value[0] < -36) {
        sunPos.value[0] = -36;
    } else if (sunPos.value[0] > 36) {
        sunPos.value[0] = 36;
    }
}

const giftShow = ref(false);

const canAction = ref(false);


const sunPos = ref([0, 0]) // x, y

const giftPos: Ref<[number | null, number | null]> = ref([null, null]); // x, y
const giftStartPos: Ref<[number, number]> = ref([0, 0]); // 起始点
const giftEndPos: Ref<[number, number]> = ref([0, 0]); // 终点
const giftMoveProgress = ref(0); // 移动进度 0-1
const giftMoveDirection = ref(1); // 移动方向 1正向 -1反向

const giftList = assets.icons;

const giftProgress = ref(0); // max = giftList.length - 1


const isGameEnd = ref(false);

const timeSpent = ref(0)

// 生成图标位置，确保之间距离不小于16
const generateIconPositions = () => {
    const icons = [...giftList, ...assets.metal];
    const positions: Array<{ src: string; left: number; top: number; delay: number }> = [];
    const minDistance = 16; // 最小距离
    const maxAttempts = 100; // 防止无限循环的最大尝试次数

    // 计算两点之间的距离
    const getDistance = (pos1: { left: number; top: number }, pos2: { left: number; top: number }) => {
        return Math.sqrt(Math.pow(pos1.left - pos2.left, 2) + Math.pow(pos1.top - pos2.top, 2));
    };

    // 检查位置是否与已有位置冲突
    const isPositionValid = (newPos: { left: number; top: number }) => {
        return positions.every(existingPos => getDistance(newPos, existingPos) >= minDistance);
    };

    icons.forEach((icon, index) => {
        let attempts = 0;
        let validPosition = false;
        let newPosition: { left: number; top: number };

        // 尝试生成不冲突的位置
        while (!validPosition && attempts < maxAttempts) {
            newPosition = {
                left: Math.random() * 100 - 50, // 扩大范围以增加成功概率
                top: Math.random() * 100 - 50
            };

            if (positions.length === 0 || isPositionValid(newPosition)) {
                validPosition = true;
                positions.push({
                    src: icon[0],
                    left: newPosition.left,
                    top: newPosition.top,
                    delay: index * 50
                });
            }
            attempts++;
        }

        // 如果无法找到不冲突的位置，使用稍微宽松的条件
        if (!validPosition) {
            console.warn(`Could not find non-conflicting position for icon ${index}, using fallback position`);
            positions.push({
                src: icon[0],
                left: Math.random() * 100 - 50,
                top: Math.random() * 100 - 50,
                delay: Math.random() * 5 + index * 0.5
            });
        }
    });

    return positions;
};

const floatIcons = ref(generateIconPositions());

// 图标聚集模拟函数 - 返回最终位置而不实际移动
const simulateGatherIcons = () => {
    const moveSpeed = 0.5; // 移动速度
    const minDistance = 16; // 最小距离
    const centerTarget = { left: 0, top: 0 }; // 目标中心点
    const threshold = 0.1; // 停止移动的阈值
    const maxIterations = 1000; // 防止无限循环的最大迭代次数

    // 创建位置副本用于模拟
    const simulatedPositions = floatIcons.value.map(icon => ({
        src: icon.src,
        left: icon.left,
        top: icon.top,
        delay: icon.delay
    }));

    // 计算两点之间的距离
    const getDistance = (pos1: { left: number; top: number }, pos2: { left: number; top: number }) => {
        return Math.sqrt(Math.pow(pos1.left - pos2.left, 2) + Math.pow(pos1.top - pos2.top, 2));
    };

    // 检查位置是否与其他图标冲突
    const isPositionValid = (newPos: { left: number; top: number }, currentIndex: number, positions: typeof simulatedPositions) => {
        return positions.every((icon, index) => {
            if (index === currentIndex) return true;
            return getDistance(newPos, icon) >= minDistance;
        });
    };

    // 向目标点移动，但避免碰撞
    const moveTowardsTarget = (currentPos: { left: number; top: number }, targetPos: { left: number; top: number }, iconIndex: number, positions: typeof simulatedPositions) => {
        const dx = targetPos.left - currentPos.left;
        const dy = targetPos.top - currentPos.top;
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance < threshold) {
            return currentPos; // 已经足够接近目标
        }

        // 计算移动方向的单位向量
        const unitX = dx / distance;
        const unitY = dy / distance;

        // 计算新位置
        const newPos = {
            left: currentPos.left + unitX * moveSpeed,
            top: currentPos.top + unitY * moveSpeed
        };

        // 检查新位置是否会产生碰撞
        if (isPositionValid(newPos, iconIndex, positions)) {
            return newPos;
        } else {
            // 如果会碰撞，尝试绕行
            const angles = [Math.PI / 4, -Math.PI / 4, Math.PI / 2, -Math.PI / 2, 3 * Math.PI / 4, -3 * Math.PI / 4];

            for (const angle of angles) {
                const rotatedX = unitX * Math.cos(angle) - unitY * Math.sin(angle);
                const rotatedY = unitX * Math.sin(angle) + unitY * Math.cos(angle);

                const alternativePos = {
                    left: currentPos.left + rotatedX * moveSpeed * 0.5,
                    top: currentPos.top + rotatedY * moveSpeed * 0.5
                };

                if (isPositionValid(alternativePos, iconIndex, positions)) {
                    return alternativePos;
                }
            }

            // 如果所有方向都被阻挡，保持原位置
            return currentPos;
        }
    };

    // 模拟聚集过程
    let iterations = 0;
    while (iterations < maxIterations) {
        let hasMovement = false;

        // 创建新的位置数组
        const newPositions = simulatedPositions.map((icon, index) => {
            const oldPos = { left: icon.left, top: icon.top };
            const newPos = moveTowardsTarget(oldPos, centerTarget, index, simulatedPositions);

            // 检查是否有移动
            if (Math.abs(newPos.left - oldPos.left) > threshold || Math.abs(newPos.top - oldPos.top) > threshold) {
                hasMovement = true;
            }

            return {
                ...icon,
                left: newPos.left,
                top: newPos.top
            };
        });

        // 更新模拟位置
        simulatedPositions.splice(0, simulatedPositions.length, ...newPositions);

        // 如果没有移动，说明已经收敛
        if (!hasMovement) {
            console.log(`图标聚集模拟完成！迭代次数: ${iterations}`);
            break;
        }

        iterations++;
    }

    if (iterations >= maxIterations) {
        console.warn('图标聚集模拟达到最大迭代次数限制');
    }

    // 返回最终位置
    return simulatedPositions;
};

const showEndAni = ref(false);

async function gameEnd() {

    fetch('/api/score', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            region: props.userdata.region,
            store: props.userdata.store,
            name: props.userdata.username,
            time: timeSpent.value / 1000,
        })
    }).then(_ => {
        fetch('/api/score', {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        })
            .then(res => res.json())
            .then(data => {
                leaderBoard.value = data;
            });
    })

    document.querySelector('.bed')?.animate([
        { transform: 'translateY(150%)' },
        { transform: 'translateY(0)' },
    ], {
        duration: 600,
        easing: 'cubic-bezier(0.4, 0, 1, 0.5)',
        fill: 'forwards',
    });
    sunEle.value?.jumpTo('落下');


    ; (document.querySelector('.p-machine') as HTMLDivElement).style.animationDirection = 'reverse';
    (document.querySelectorAll('.action img') as NodeListOf<HTMLImageElement>).forEach(img => {
        img.style.animationDirection = 'reverse';
    });

    document.querySelector('.sun-ani-wrapper')?.animate([
        { transform: 'translateY(8%) translateX(-50%)', left: '50%', bottom: '23%', width: '60vw' },
    ], {
        duration: 1100,
        easing: 'ease-in-out',
        fill: 'forwards',
    }).finished


    isGameEnd.value = true;

    // 模拟图标聚集并获取最终位置
    const finalPositions = simulateGatherIcons();

    await wait(0)
    floatIcons.value = finalPositions;

    await wait(1800)

    showEndAni.value = true;
    sunEndEle.value?.jumpTo('all');

    await wait(3400);
    showScore.value = true;




    document.querySelector('.bed')?.animate([
        { transform: 'translateY(0)' },
        { transform: 'translateY(150%)' },
    ], {
        duration: 600,
        easing: 'cubic-bezier(0.4, 0, 1, 0.5)',
        fill: 'forwards',
    });



}

const leaderBoard = ref([
    {
        "name": "测试用户",
        "time": 1.7116000000000005,
        "region": "奥莱",
        "store": "北京斯普瑞斯"
    },
    {
        "name": "阿迪斯",
        "time": 1.9645,
        "region": "奥莱",
        "store": "北京斯普瑞斯"
    },
    {
        "name": "Mike",
        "time": 45.5,
        "region": "大北区",
        "store": "大连恒隆广场"
    },
    {
        "name": "小白",
        "time": 83.2,
        "region": "大西区",
        "store": "太原万象城"
    },
    {
        "name": "小明",
        "time": 98.2,
        "region": "大西区",
        "store": "太原万象城"
    },
    {
        "name": "Elena",
        "time": 122.2,
        "region": "大南区",
        "store": "深圳湾万象城"
    }

])

const fmtTime = (time: number) => {
    time = Math.round(time);
    // 将时间格式化为 mm:ss
    const minutes = Math.floor(time / 60);
    const seconds = time % 60;
    return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
};


const showScore = ref(false)

const showLastPage = ref(false);

const sunAniEndRules = ref([
    { name: 'all', frame: 164, loop: 1, pauseAfter: false, duration: 33 },
    { name: '左右跳', frame: 66, loop: 0, pauseAfter: true, duration: 33 },
    { name: '落下', frame: 32, loop: 1, pauseAfter: false, duration: 33 },
    { name: 'loop', frame: 33, loop: 0, pauseAfter: true, duration: 33 },
])
import QRCode from 'qrcode';
const qrcodeUrl = ref('');

QRCode.toDataURL(`https://arcteryx-game-demo.xn--876a.net`, {
    width: 256,
}).then(url => {
    qrcodeUrl.value = url;
}).catch(err => {
    console.error('生成二维码失败:', err);
});



async function finishCollect() {
    document.querySelector('.finish-collect')?.animate([
        { transform: 'scale(1)' },
        { transform: 'scale(0)' },
    ], {
        duration: 500,
        easing: 'cubic-bezier(0.53,-0.7, 0.25, 1)',
        fill: 'forwards',
    })
    document.querySelector('.wecare-title')?.animate([
        { transform: 'scale(1)' },
        { transform: 'scale(0)' },
    ], {
        duration: 500,
        easing: 'ease-in-out',
        fill: 'forwards',
    })

    await document.querySelector('.lines')?.animate([
        { transform: 'translateX(150%)' }], {
        duration: 500,
        easing: 'ease-in-out',
        fill: 'forwards',
    }).finished
    await sunEndEle.value?.jumpToSoftly('落下');
    await document.querySelector('.bar-container')?.animate([
        { transform: 'translateY(300%)' }], {
        duration: 500,
        easing: 'ease-in-out',
        fill: 'forwards',
    }).finished
    //@ts-ignore
    document.querySelector('.lines').style.display = 'none';
    //@ts-ignore
    document.querySelector('.bar-container').style.display = 'none';

    showLastPage.value = true;

    setTimeout(() => {
        if (!posterHasChangedToPage2.value) posterHasChangedToPage2.value = true;
    }, 8000);

}

// 重置游戏状态的函数
function resetGame() {
    emit('restart')
}

const posterHasChangedToPage2 = ref(false);
const posterAni = useTemplateRef('gui-ani-end-post');
watch(posterHasChangedToPage2, (newVal) => {
    if (newVal) {
        posterAni.value?.jumpTo('p2');
    }
});

let hasSwapX = 0
function posterSwap(e: PointerEvent) {
    if (posterHasChangedToPage2.value) return;
    if (e.buttons === 1) {
        hasSwapX += e.offsetX
        if (Math.abs(hasSwapX) > 100) {
            posterHasChangedToPage2.value = true;
        }
    }
}
</script>

<template>
    <div class="page game">

        <div class="public">

            <img src="../assets/game/床.png" alt="" class="abs bed"
                style="width: 66vw;bottom: 12%;left: 17%;">

            <AniEle :url="assets.ani.下拉蓄力提示" ref="shoot-notice" :height="334"
                :width="337" :rules="[
                    { name: '蓄力', frame: 241, loop: 2 },
                ]" class="abs arrow" style="bottom: 7%;width: 30vw;left: 35%;"
                @pointerdown.once="shoot" />

            <div class="sun-ani-wrapper abs" v-if="!showEndAni" :style="{
                width: '60vw',
                zIndex: 99,
                pointerEvents: 'none',
                bottom: `calc(21% + ${sunPos[1]}vw)`,
                left: `calc(49% + ${sunPos[0]}vw)`,
                transform: `translateX(-50%)`,
                transition: transitionOn ? 'all 0.1s ease' : undefined
            }">

                <!-- AniEle 组件现在只关心自己的内容，不再有复杂的外部样式 -->
                <AniEle :url="assets.ani.小太阳总" ref="sun-ani" class="sun-ani"
                    :height="1800" :width="1600" :rules="[
                        { name: '起飞前', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
                        { name: '蓄力飞', frame: 181, loop: 1, pauseAfter: false, duration: 33 },
                        { name: '天上飞', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
                        { name: '落下', frame: 382, loop: 0, pauseAfter: false, duration: 33 },
                    ]" style="width: 100%; height: auto;" />
            </div>
        </div>

        <div v-if="canAction && !showLastPage">
            <img src="../assets/game/鼓风机.png" class="abs p-machine"
                style="bottom: -40%; width: 66vw; left: 17%; transform-origin: 50% 63%; transition: all 0.2s;"
                :style="{ transform: `rotate(${gDeg}deg)` }" />
            <div class="action">
                <img draggable="false" :style="{ animationDelay: '0.1s' }"
                    src="../assets/game/左.png" alt="" @click="gToggle('left')">
                <img draggable="false" :style="{ animationDelay: '0.2s' }"
                    src="../assets/game/中.png" alt=""
                    @click="gToggle('center')">
                <img draggable="false" :style="{ animationDelay: '0.0s' }"
                    src="../assets/game/右.png" alt="" @click="gToggle('right')">
            </div>

            <img class="abs gift-item" v-for="(gift, index) in giftList"
                :src="gift[0]" style="width: 20vw;" v-if="!isGameEnd" :style="{
                    display: giftProgress == index ? 'block' : 'none',
                    bottom: `calc(45% + ${giftPos[1] ?? 0}vw)`, left: `calc(39.5% + ${giftPos[0] ?? 0}vw)`, transition: transitionOn ? `all 0.1s ease` : undefined
                }" alt=""
                :class="{ show: giftProgress == index, hide: giftProgress != index }">

            <img src="../assets//game/操作提示.png" class="abs prompt" alt=""
                style="width: 31%; bottom: 18%; left: 34%; ">
            <img src="../assets/game/风.png" alt="" class="abs wind">
            <img src="../assets/game/wecare.png" alt="" class="abs wecare"
                style="width: 24vw;
            left: 50%; top: 6%; transform: translateX(-50%);">
            <div class="dot" v-if="!isGameEnd">
                <div v-for="(_, index) in giftList" :key="index"
                    class="dot-item" :class="{ finished: index < giftProgress }"
                    @click="giftProgress = index">
                </div>
            </div>
        </div>

        <div class="game-end abs" v-if="isGameEnd"
            style="z-index: 2; inset: 0; height: 100%; width: 100%;pointer-events: none;">
            <div class="icon-cloud"
                style="position: absolute; left: 50%; top: 20%;">
                <img v-for="icon in floatIcons" :src="icon.src" alt="" :style="{
                    top: `${icon.top}vw`,
                    left: `${icon.left}vw`,
                    animationDelay: `${icon.delay}ms`,
                }">
            </div>
            <img src="../assets/game/wecare.png" alt="" class="abs wecare"
                style="width: 24vw;
            left: 50%; top: 6%; transform: translateX(-50%);">

            <img src="../assets/game/wecare标题.png" alt=""
                class="abs wecare-title" style="width: 72%;left: 14%;top: 12%;">


            <div class="scoreboard" v-if="showScore">
                <div class="bar-container">
                    <div class="bar"
                        v-for="(item, index) in [leaderBoard[1], leaderBoard[0], leaderBoard[2]]"
                        :key="index" :class="{
                            'first': index === 1, 'second': index === 0, 'third': index === 2
                        }">
                        <div class="name">{{ item.name }}</div>
                        <div class="time">{{ fmtTime(item.time) }}</div>
                        <div class="region">{{ item.region }}</div>
                        <div class="store">{{ item.store }}</div>
                    </div>
                </div>
                <div class="lines">
                    <div class="line"
                        v-for="(item, index) in leaderBoard.slice(3, 7)"
                        :key="index"
                        :style="{ animationDelay: index * 100 + 400 + 'ms' }">
                        <div class="rank">{{ index + 4 }}</div>
                        <div class="name">{{ item.name }}</div>
                        <div class="time">{{ fmtTime(item.time) }}</div>
                        <div class="region">{{ item.region }}</div>
                    </div>
                </div>
            </div>

            <div class="sun-ani-end-wrapper abs"
                style="pointer-events: none; inset: 0; width: 100%;z-index: 2;"
                :style="{ display: showEndAni ? 'block' : 'none' }">

                <!-- AniEle 组件现在只关心自己的内容，不再有复杂的外部样式 -->
                <AniEle :url="assets.ani.后端效果" ref="sun-ani-end"
                    class="sun-ani-end" :height="2462" :width="1179"
                    :rules="sunAniEndRules"
                    style="width: 100%; height: auto;" />
            </div>

            <img src="../assets/game/完成收集.png" alt="" v-if="showScore"
                class="finish-collect abs" @click.once="finishCollect"
                style="bottom: 8%;left: 33%;width: 34vw;animation: scale-in 0.3s ease-out;pointer-events: all;">


        </div>

        <div class="last-page" v-if="showLastPage"
            style="z-index: 0;position: absolute; inset: 0;height: 100%; width: 100%; pointer-events: none;">
            <AniEle :url="assets.ani.结尾主标" :width="925" :height="340"
                :rules="[{ name: 'main', frame: 41, loop: 1, pauseAfter: true, duration: 33, reverse: false }]"
                style="position: absolute;top: 13%;width: 80%;left: 11%; pointer-events:none;"
                ref="main-logo" />
            <div class="poster-container" @pointermove="posterSwap"
                style="position: absolute;top: 29.3%;left: 37.2%;width: 57.3%; height: 38%; overflow: hidden;pointer-events: all;">
                <AniEle :url="assets.ani.海报" ref="gui-ani-end-post"
                    style="width: 100%;" class="gui-ani-end-post" :height="940"
                    :width="671" :rules="[
                        { name: 'p1', frame: 32, loop: 1, pauseAfter: true, duration: 33 },
                        { name: 'p2', frame: 46, loop: 1, pauseAfter: true, duration: 33 },
                    ]" />
            </div>
            <AniEle :url="assets.ani.线" ref="gui-ani-end" class="gui-ani-end"
                :height="2462" :width="1179" :rules="[
                    { name: 'all', frame: 54, loop: 1, pauseAfter: false, duration: 16 },
                ]"
                style="width: 100%; height: auto;position: absolute;inset: 0;pointer-events: none;" />
            <img src="../assets/game/床.png" alt="" class="abs last-bed"
                style="width: 66vw;bottom: -19%;left: 17%;">

            <img src="../assets/game/分享海报.png" alt="" class="abs"
                style="width: 34vw;bottom: -19%;left: 15%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; pointer-events: all;">
            <img src="../assets/game/再玩一次.png" alt="" class="abs"
                @click="resetGame"
                style="width: 34vw;bottom: -19%;left: 51%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; animation-delay: 200ms; pointer-events: all;">

            <div class="time-spent abs" style="left: 10%; top:44%;width: 24%;height: 23%; display: flex;
            align-items: center; flex-direction: column;">
                <div class="line-1"
                    style="display: flex; align-items: center; gap: 1vw; animation: line-in 0.5s ease-out 0.6s forwards;transform: translateX(-210%);">
                    <div class="username" style="font-size: 2.9vw;">{{
                        userdata.username }}</div>
                    <div class="cost-info"
                        style="font-size: 2.9vw; color: white; display: flex;align-items: center;justify-content: center;background-color: black;padding: 0 1.2vw; height: 4.5vw; border-radius: 4vw;">
                        用时</div>
                </div>

                <div class="time"
                    style="font-size: 10vw;animation: line-in 0.5s ease-out 0.8s forwards;transform: translateX(-210%);">
                    {{ fmtTime(timeSpent / 1000) }}</div>

                <img :src="qrcodeUrl" alt=""
                    style="width: 100%;bottom:7%;position: absolute;animation: line-in 0.5s ease-out 1s forwards;transform: translateX(-210%);">
            </div>

            <div class="region-area abs"
                style="left: 10%; top:30%;width: 24%;height: 10%;gap:2vw; display: flex;animation: line-in 0.5s ease-out 0.4s forwards;transform: translateX(-210%);
            align-items: center; flex-direction: column;justify-content: center;">
                <div class="region"
                    style="width: 20vw; background-color: white;font-size: 3vw;text-align: center;height: 5.2vw;line-height: 5.2vw; border-radius: 4.5vw;">
                    {{ userdata.region }}</div>
                <div class="store" style="font-size: 2.9vw; color: gray;">{{
                    userdata.store }}</div>
            </div>

        </div>



        <div v-if="giftShow" class="gift-popup">
            <img :src="giftList[giftProgress][1]" alt="" class="abs"
                style="width: 82%; left: 9%; top: 11%;">
            <img src="../assets/game/收下福利.png" alt="" class="abs"
                style="width: 14%; left: 43%; top: 54%;" @click="gameLoop()">
        </div>



    </div>
</template>

<style lang="scss">
@keyframes last-btn-in {
    0% {
        bottom: -19%;
    }

    100% {
        bottom: 8%;
    }
}

@keyframes fade-in {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes last-bed-in {
    0% {
        bottom: -19%;
        scale: 1;
    }

    100% {
        bottom: 1.5%;
        scale: 0.55;
    }
}

.last-bed {
    z-index: -1;
    animation: last-bed-in 0.5s ease-in-out forwards;
}


@keyframes scale-out {
    0% {
        scale: 1;
    }

    100% {
        scale: 0;
    }
}

@keyframes bar-in {
    from {
        transform: translateY(300%);
    }

    to {
        transform: translateY(0%);
    }
}

@keyframes line-in {
    from {
        transform: translateX(-210%);
    }

    to {
        transform: translateX(-0%);

    }
}

.scoreboard {
    position: absolute;
    top: 44%;
    width: 100%;

    .bar-container {
        width: 100%;
        justify-content: center;
        align-items: center;
        display: flex;
        gap: 2vw;
    }

    .bar {
        position: relative;
        height: 60vw;
        width: 26vw;
        background-size: contain;
        background-repeat: no-repeat;
        mask-image: linear-gradient(to bottom, black, black, transparent);
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 1.5vw;
        animation: bar-in 0.7s ease-out forwards;
        transform: translateY(150%);

        .name {
            font-size: 4.5vw;
        }

        .time {
            font-size: 3vw;
        }

        .region {
            font-size: 3vw;
            color: white;
            background-color: #7EA0CA;
            padding: 0 2vw;
            border-radius: 2vw;
        }

        .store {
            max-width: 13vw;
            text-align: center;
            font-size: 2.4vw;
            color: gray;
        }

        &.first {
            top: 3vw;
            background-image: url('../assets/game/first.png');
            animation-delay: 0ms;
        }

        &.second {
            background-image: url('../assets/game/second.png');
            animation-delay: 250ms;
            top: 9vw;
        }

        &.third {
            background-image: url('../assets/game/third.png');
            animation-delay: 500ms;
            top: 9vw;
        }
    }

    .lines {
        display: flex;
        position: relative;
        top: -5vw;
        flex-direction: column;
        align-items: center;
        gap: 1vw;

        .line {
            display: flex;
            align-items: center;
            justify-content: space-between;
            width: 80%;
            font-size: 3.2vw;
            background-color: #FFFFFF;
            padding: 0 2vw;
            height: 8vw;
            border-radius: 8vw;
            animation: line-in 0.5s ease-out forwards;
            transform: translateX(-150%);

            .rank {
                // italic
                font-style: italic;
                flex: 1;
                font-size: 4vw;
                text-align: center;
                color: #7EA0CA;
            }

            .name {
                flex: 2;
                text-align: center;
                border-right: .35vw solid black;
            }

            .time {
                flex: 2;
                text-align: center;
                border-right: .35vw solid black;
            }

            .region {
                flex: 2;
                color: gray;
                text-align: center;
            }
        }
    }
}


.wecare-title {
    animation: scale-in 0.4s ease-in-out forwards;
    animation-delay: 3.9s;
    scale: 0;
}

.icon-cloud {
    animation: scale-out 0.4s ease-in-out forwards;
    animation-delay: 3.5s;

    img {
        position: absolute;
        width: 16vw;
        transition: all 4s ease;
        animation: scale-in 0.4s ease-in-out forwards;
        transform: translate(-50%, -50%);
        transform-origin: left top;
        scale: 0;
    }
}

@keyframes gift-popup-bg {
    0% {
        backdrop-filter: blur(0px);
        opacity: 0;
    }

    100% {
        backdrop-filter: blur(16px);
        opacity: 1;
    }
}

.gift-popup {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 1000;
    backdrop-filter: blur(0px);
    opacity: 0;
    animation: gift-popup-bg 1.2s ease-in-out 0.7s forwards;
}

.dot {
    position: absolute;
    top: 10%;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 2vw;

    .dot-item {
        width: 2vw;
        height: 2vw;
        border-radius: 50%;
        background-color: #fff;
        transition: all 0.2s ease-in-out;
    }

    .dot-item.finished {
        background-color: #7EA0CA;
    }
}


@keyframes scale-in {
    0% {
        scale: 0;
    }

    100% {
        scale: 1;
    }

}

@keyframes warp-in {
    0% {
        bottom: -40%
    }

    100% {
        bottom: -13%;
    }

}

@keyframes prompt-in {
    0% {
        rotate: 20deg;
        scale: 0;
    }

    100% {
        rotate: 0;
        scale: 1;
    }

}

@keyframes prompt-out {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }

}

.prompt {
    transform-origin: 21% 99%;
    animation: prompt-in 0.8s cubic-bezier(0.71, 0.13, 0.43, 2.5) forwards,
        prompt-out 0.8s cubic-bezier(0.71, 0.13, 0.43, 2.5) 2s forwards;
}

.p-machine {
    animation: warp-in 0.5s ease-out forwards;
}

.abs {
    position: absolute;
}

.wind {
    z-index: 11;
    pointer-events: none;
    opacity: 0;
}

.action {
    display: flex;
    position: absolute;
    bottom: 19vw;
    left: 50%;
    transform: translateX(-50%);
    gap: 2vw;

    img {
        flex: 1;
        width: 28vw;
        scale: 0;
        animation: scale-in 0.4s ease-in-out forwards;
    }
}
</style>
