<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch, nextTick, computed } from 'vue';
import { assetUrl } from '@/commons/assets.ts'
import { playGame6Music } from '@/commons/music'

const props = defineProps<{
    imageUrls: Record<string, string>
    countdownInterval: number
    isDivDescVisible: boolean
    tick: number
    rank: number
}>();

const emit = defineEmits<{
    touch: [mole: boolean]
    scoreChange: [delta: number]
}>();

// ========== 常量 ==========
const ROAD_TOP = 421.9;
const ROAD_HEIGHT = 1624 - ROAD_TOP;
const HORSE_W = 131;
const HORSE_H = 285;
const HORSE_BOTTOM_PCT = 19.11;
const ITEM_SIZE = 80;
const GAME_DURATION = 60;

const LEFT_LANE_X = 170;
const RIGHT_LANE_X = 470;

// ========== 马帧 ==========
const HORSE_FRAME_COUNT = 21;
const horseFrames = Array.from({ length: HORSE_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/horse/1-ma_${String(i).padStart(2, '0')}.png`)
);

// ========== 金币/炸弹帧 ==========
const JINBI_FRAME_COUNT = 25;
const jinbiFrames = Array.from({ length: JINBI_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/jinbi/1-yuanbao_${String(i).padStart(2, '0')}.png`)
);

const BOM_FRAME_COUNT = 28;
const bomFrames = Array.from({ length: BOM_FRAME_COUNT }, (_, i) =>
    assetUrl(`game3/bom/1-zha_${String(i).padStart(2, '0')}.png`)
);

const fudaiUrl = assetUrl('game3/icon_fudai.webp');
const dileiUrl = assetUrl('game3/icon_dilei.webp');

// ========== 马状态 ==========
const horseLane = ref<'left' | 'right'>('left');
const horseFrameIndex = ref(0);

const horseX = ref(LEFT_LANE_X);
const horseTargetX = ref(LEFT_LANE_X);

const switchToLeft = () => {
    if (horseLane.value !== 'left') {
        horseLane.value = 'left';
        horseTargetX.value = LEFT_LANE_X;
    }
};

const switchToRight = () => {
    if (horseLane.value !== 'right') {
        horseLane.value = 'right';
        horseTargetX.value = RIGHT_LANE_X;
    }
};

// ========== 键盘控制 ==========
const handleKeydown = (e: KeyboardEvent) => {
    if (!props.isDivDescVisible) return;
    if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') {
        switchToLeft();
    } else if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') {
        switchToRight();
    }
};

// ========== 路背景加速滚动 ==========
const roadOffset = ref(0);
let roadRafId: number | undefined;
let roadLastTs = 0;
const BASE_ROAD_SPEED = 80;
const MAX_ROAD_SPEED = 400;
const gameElapsed = ref(0);
const currentRoadSpeed = ref(BASE_ROAD_SPEED);

const startRoadScroll = () => {
    stopRoadScroll();
    roadLastTs = 0;
    gameElapsed.value = 0;
    const startTs = performance.now();

    const tick = (ts: number) => {
        if (!props.isDivDescVisible) {
            roadRafId = requestAnimationFrame(tick);
            return;
        }
        if (!roadLastTs) roadLastTs = ts;
        const dt = Math.min(ts - roadLastTs, 100);
        roadLastTs = ts;

        gameElapsed.value = (ts - startTs) / 1000;
        const progress = Math.min(gameElapsed.value / GAME_DURATION, 1);
        currentRoadSpeed.value = BASE_ROAD_SPEED + (MAX_ROAD_SPEED - BASE_ROAD_SPEED) * progress;

        roadOffset.value += currentRoadSpeed.value * dt / 1000;

        roadRafId = requestAnimationFrame(tick);
    };
    roadRafId = requestAnimationFrame(tick);
};

const stopRoadScroll = () => {
    if (roadRafId) {
        cancelAnimationFrame(roadRafId);
        roadRafId = undefined;
    }
};

// ========== 持续道具生成系统 ==========
type ItemKind = 'coin' | 'bomb';

interface RoadItem {
    id: number;
    kind: ItemKind;
    lane: 'left' | 'right';
    y: number;
    collected: boolean;
    animFrame: number;
    animTimer: ReturnType<typeof setTimeout> | undefined;
}

const roadItems = ref<RoadItem[]>([]);
const effectAnims = ref<{ id: number; kind: ItemKind; frame: number; x: number; y: number }[]>([]);

let itemIdCounter = 0;
let lastItemY = 0;
const MIN_ITEM_SPACING = 250;
const MAX_ITEM_SPACING = 400;
const ITEM_GEN_INTERVAL = 1500;

function seededRandom(seed: number) {
    const x = Math.sin(seed * 12.9898 + 78.233) * 43758.5453;
    return x - Math.floor(x);
}

function generateNewItem() {
    if (!props.isDivDescVisible) return;
    
    const seed = Date.now() + itemIdCounter;
    const kind: ItemKind = seededRandom(seed) < 0.55 ? 'coin' : 'bomb';
    const lane: 'left' | 'right' = seededRandom(seed + 1000) < 0.5 ? 'left' : 'right';
    
    const spacing = MIN_ITEM_SPACING + seededRandom(seed + 2000) * (MAX_ITEM_SPACING - MIN_ITEM_SPACING);
    const startY = -ITEM_SIZE;
    
    const newItem: RoadItem = {
        id: itemIdCounter++,
        kind,
        lane,
        y: startY,
        collected: false,
        animFrame: 0,
        animTimer: undefined,
    };
    
    roadItems.value.push(newItem);
    
    setTimeout(generateNewItem, ITEM_GEN_INTERVAL);
}

function cleanupOffscreenItems() {
    const screenBottom = roadOffset.value + ROAD_HEIGHT;
    roadItems.value = roadItems.value.filter(item => {
        const itemBottom = item.y + ITEM_SIZE;
        return itemBottom > roadOffset.value - 100 && item.y < screenBottom + 100;
    });
}




// ========== 碰撞检测 ==========
const horseBottomY = ROAD_HEIGHT * (HORSE_BOTTOM_PCT / 100);
const horseTopY = horseBottomY - HORSE_H;

const checkCollisions = () => {
    const horseCenterX = horseX.value + HORSE_W / 2;
    const horseTopCenterY = horseTopY + HORSE_H * 0.15;
    const horseRadius = HORSE_W * 0.35;

    for (const item of roadItems.value) {
        if (item.collected) continue;

        const itemX = item.lane === 'left' ? LEFT_LANE_X : RIGHT_LANE_X;
        const itemVisualY = item.y;
        const itemCenterX = itemX + ITEM_SIZE / 2;
        const itemCenterY = itemVisualY + ITEM_SIZE / 2;

        const dist = Math.hypot(horseCenterX - itemCenterX, horseTopCenterY - itemCenterY);

        if (dist < horseRadius + ITEM_SIZE * 0.35) {
            item.collected = true;
            playCollectEffect(item, itemX, itemVisualY);
        }
    }
};

const playCollectEffect = (item: RoadItem, x: number, y: number) => {
    if (item.kind === 'coin') {
        emit('scoreChange', 5);
        playGame6Music(1);
    } else {
        emit('scoreChange', -3);
        playGame6Music(2);
    }

    const animId = Date.now() + Math.random();
    const totalFrames = item.kind === 'coin' ? JINBI_FRAME_COUNT : BOM_FRAME_COUNT;
    const frameDuration = 1000 / totalFrames;

    effectAnims.value.push({ id: animId, kind: item.kind, frame: 0, x, y });

    let frameIdx = 0;
    const tick = () => {
        frameIdx++;
        if (frameIdx >= totalFrames) {
            effectAnims.value = effectAnims.value.filter(a => a.id !== animId);
            return;
        }
        const anim = effectAnims.value.find(a => a.id === animId);
        if (anim) anim.frame = frameIdx;
        item.animTimer = setTimeout(tick, frameDuration);
    };
    item.animTimer = setTimeout(tick, frameDuration);
};

// ========== 主循环 ==========
let mainRafId: number | undefined;
let mainLastTs = 0;
let perSecondTimer: ReturnType<typeof setInterval> | undefined;

let horseFrameAccum = 0;

const startMainLoop = () => {
    stopMainLoop();
    mainLastTs = 0;
    horseFrameAccum = 0;

    const tick = (ts: number) => {
        if (!props.isDivDescVisible) {
            mainRafId = requestAnimationFrame(tick);
            return;
        }
        if (!mainLastTs) mainLastTs = ts;
        const dt = Math.min(ts - mainLastTs, 200);
        mainLastTs = ts;

        horseFrameAccum += dt;
        while (horseFrameAccum >= 48) {
            horseFrameAccum -= 48;
            horseFrameIndex.value = (horseFrameIndex.value + 1) % HORSE_FRAME_COUNT;
        }

        const lerpFactor = 1 - Math.pow(0.001, dt / 1000);
        horseX.value += (horseTargetX.value - horseX.value) * lerpFactor;

        checkCollisions();
        
        for (const item of roadItems.value) {
            if (!item.collected) {
                item.y += currentRoadSpeed.value * dt / 1000;
            }
        }
        
        cleanupOffscreenItems();

        mainRafId = requestAnimationFrame(tick);
    };
    mainRafId = requestAnimationFrame(tick);

    perSecondTimer = setInterval(() => {
        if (props.isDivDescVisible) {
            emit('scoreChange', 2);
        }
    }, 1000);
};

const stopMainLoop = () => {
    if (mainRafId) {
        cancelAnimationFrame(mainRafId);
        mainRafId = undefined;
    }

    if (perSecondTimer) {
        clearInterval(perSecondTimer);
        perSecondTimer = undefined;
    }
};

// ========== 生命周期 ==========
onMounted(() => {
    window.addEventListener('keydown', handleKeydown);
    nextTick(() => {
        startRoadScroll();
        startMainLoop();
        setTimeout(generateNewItem, 1000);
    });
});

onBeforeUnmount(() => {
    window.removeEventListener('keydown', handleKeydown);
    stopRoadScroll();
    stopMainLoop();
    for (const item of roadItems.value) {
        if (item.animTimer) clearTimeout(item.animTimer);
    }
    roadItems.value = [];
});

watch(() => props.isDivDescVisible, (visible) => {
    if (visible) {
        nextTick(() => {
            roadItems.value = [];
            effectAnims.value = [];
            roadOffset.value = 0;
            gameElapsed.value = 0;
            startRoadScroll();
            startMainLoop();
            setTimeout(generateNewItem, 1000);
        });
    } else {
        stopRoadScroll();
        stopMainLoop();
        for (const item of roadItems.value) {
            if (item.animTimer) clearTimeout(item.animTimer);
        }
        roadItems.value = [];
        effectAnims.value = [];
    }
}, { immediate: true });
</script>

<template>
    <div class="h5-page game-stage">
        <div class="only-bg"></div>
        <div class="content-bg">
            <div class="road-track" :style="{ transform: `translateY(${roadOffset % ROAD_HEIGHT}px)` }">
                <div class="road-inner"></div>
                <div class="road-inner"></div>
                <div class="road-inner"></div>
            </div>

            <!-- 道具 -->
            <template v-for="item in roadItems" :key="item.id">
                <img
                    v-if="!item.collected"
                    :src="item.kind === 'coin' ? fudaiUrl : dileiUrl"
                    class="road-item"
                    :class="`item-lane-${item.lane}`"
                    :style="{
                        top: `${item.y + roadOffset}px`,
                    }"
                />
            </template>

            <!-- 碰撞特效 -->
            <template v-for="anim in effectAnims" :key="anim.id">
                <img
                    :src="(anim.kind === 'coin' ? jinbiFrames : bomFrames)[anim.frame]"
                    class="effect-anim"
                    :style="{ left: `${anim.x}px`, top: `${anim.y}px` }"
                />
            </template>

            <!-- 马 -->
            <div class="horse-wrapper" :style="{ left: `${horseX}px`, bottom: `${HORSE_BOTTOM_PCT}%` }">
                <img
                    v-for="(url, idx) in horseFrames"
                    :key="idx"
                    :src="url"
                    class="horse-frame"
                    :class="{ active: idx === horseFrameIndex }"
                    alt=""
                />
            </div>
        </div>

        <Transition name="div-desc-slide" appear>
            <div v-if="isDivDescVisible" class="div-desc">
                <span class="desc-clock" aria-hidden="true"></span>
                <span class="desc-time">{{ countdownInterval }}</span>
            </div>
        </Transition>
        <div class="img-logo"></div>
        <div class="img-hydt"></div>
        <div class="img-hammer"></div>
        <div class="img-left" @click="switchToLeft"></div>
        <div class="img-right" @click="switchToRight"></div>
    </div>
</template>

<style scoped>
.game-stage {
    position: absolute;
    width: 750px;
    height: 1624px;
    padding: 0;
}

.only-bg {
    position: absolute;
    top: 0;
    left: var(--stage-viewport-left, 0);
    width: var(--stage-viewport-width, 750px);
    height: 421.9px;
    background: v-bind('imageUrls.bg3') center / cover no-repeat;
}

.content-bg {
    position: absolute;
    top: 421.9px;
    left: var(--stage-viewport-left, 0);
    width: var(--stage-viewport-width, 750px);
    height: 1202.1px;
    overflow: hidden;
    z-index: 1;
}

.road-track {
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    flex-direction: column;
}

.road-inner {
    width: 100%;
    height: 1202.1px;
    background: v-bind('imageUrls.bg4') center / cover no-repeat;
    flex-shrink: 0;
}

.road-item {
    position: absolute;
    width: 80px;
    height: 80px;
    z-index: 5;
    pointer-events: none;
}

.item-lane-left {
    left: 170px;
}

.item-lane-right {
    left: 470px;
}

.effect-anim {
    position: absolute;
    width: 120px;
    height: 120px;
    z-index: 10;
    pointer-events: none;
}

.horse-wrapper {
    position: absolute;
    width: 131px;
    height: 285px;
    z-index: 8;
}

.horse-frame {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    opacity: 0;
    pointer-events: none;
}

.horse-frame.active {
    opacity: 1;
}

.img-hydt {
    position: absolute;
    width: 454px;
    height: 181px;
    top: 174px;
    left: 52%;
    transform: translate(-50%, -50%);
    background: v-bind('imageUrls.hydt') center / cover;
}

.img-left {
    position: absolute;
    width: 128px;
    height: 128px;
    left: 144px;
    bottom: 5.48%;
    z-index: 20;
    background: v-bind('imageUrls.left') center / cover no-repeat;
    cursor: pointer;
}

.img-right {
    position: absolute;
    width: 128px;
    height: 128px;
    right: 144px;
    bottom: 5.48%;
    z-index: 20;
    background: v-bind('imageUrls.right') center / cover no-repeat;
    cursor: pointer;
}

.img-hammer {
    width: 148px;
    height: 148px;
    background: v-bind('imageUrls.hammer') center / cover;
    position: absolute;
    left: 50%;
    bottom: 100px;
    transform: translate(-50%, 0);
}

.div-desc {
    position: absolute;
    top: 150px;
    left: var(--stage-viewport-left, 0);
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 24px;
    width: 180px;
    height: 80px;
    border-radius: 0 56px 56px 0;
    background: rgba(40, 12, 8, 0.48);
    color: #fff;

    .desc-clock {
        position: absolute;
        left: 20px;
        width: 38px;
        height: 44px;
        border-radius: 50%;
        background: v-bind('imageUrls.clock') center / cover;
    }

    .desc-time {
        position: absolute;
        right: 40px;
        color: white;
        font-size: 35pt;
        line-height: 1;
    }
}

.div-desc-slide-enter-active {
    transition:
        transform 360ms ease-out 220ms,
        opacity 360ms ease-out 220ms;
}

.div-desc-slide-leave-active {
    transition:
        transform 260ms ease-in,
        opacity 260ms ease-in;
}

.div-desc-slide-enter-from,
.div-desc-slide-leave-to {
    opacity: 0;
    transform: translateX(-110%);
}

.div-desc-slide-enter-to,
.div-desc-slide-leave-from {
    opacity: 1;
    transform: translateX(0);
}

.img-logo {
    position: absolute;
    top: 46px;
    left: 20px;
    width: 428px;
    height: 77px;
    background: v-bind('imageUrls.logo') center / cover;
}
</style>
