<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from 'vue';
import { isGameSocketConnected } from '@/composables/useGameSocket';

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

const emit = defineEmits<{
    touch: [value: number]
}>()

const score = ref(0)
const FULL_ROTATION = Math.PI * 2
const DRAG_RESISTANCE = 0.82
const INERTIA_FRICTION = 0.94
const MIN_INERTIA_VELOCITY = 0.05
const coinRef = ref<HTMLElement | null>(null)
const coinRotation = ref(0)

let activePointerId: number | null = null
let previousAngle = 0
let clockwiseAngle = 0
let angularVelocity = 0
let inertiaFrame: number | undefined

function getPointerAngle(event: PointerEvent) {
    const rect = coinRef.value?.getBoundingClientRect()
    if (!rect) return 0

    const centerX = rect.left + rect.width / 2
    const centerY = rect.top + rect.height / 2

    return Math.atan2(event.clientY - centerY, event.clientX - centerX)
}

function normalizeAngle(angle: number) {
    if (angle > Math.PI) return angle - FULL_ROTATION
    if (angle < -Math.PI) return angle + FULL_ROTATION
    return angle
}

function startRotation(event: PointerEvent) {
    if (props.isGameEnded) return
    if (activePointerId !== null) return

    stopInertia()
    activePointerId = event.pointerId
    previousAngle = getPointerAngle(event)
    clockwiseAngle = 0
    angularVelocity = 0
    coinRef.value?.setPointerCapture(event.pointerId)
}

function rotateCoin(event: PointerEvent) {
    if (props.isGameEnded) return
    if (event.pointerId !== activePointerId) return

    const currentAngle = getPointerAngle(event)
    const angleDelta = normalizeAngle(currentAngle - previousAngle)
    previousAngle = currentAngle

    if (angleDelta <= 0) {
        angularVelocity = 0
        return
    }

    const rotationDelta = angleDelta * 180 / Math.PI * DRAG_RESISTANCE
    coinRotation.value += rotationDelta
    angularVelocity = angularVelocity * 0.55 + rotationDelta * 0.45
    clockwiseAngle += angleDelta

    while (clockwiseAngle >= FULL_ROTATION) {
        clockwiseAngle -= FULL_ROTATION
        if (!isGameSocketConnected.value) {
            return
        }
        score.value += 5
        emit('touch', score.value)
    }
}

function stopRotation(event: PointerEvent) {
    if (event.pointerId !== activePointerId) return

    if (coinRef.value?.hasPointerCapture(event.pointerId)) {
        coinRef.value.releasePointerCapture(event.pointerId)
    }
    activePointerId = null
    clockwiseAngle = 0
    startInertia()
}

function stopInertia() {
    if (inertiaFrame !== undefined) {
        cancelAnimationFrame(inertiaFrame)
        inertiaFrame = undefined
    }
}

function startInertia() {
    stopInertia()
    angularVelocity = Math.max(0, angularVelocity)

    const animate = () => {
        angularVelocity *= INERTIA_FRICTION

        if (Math.abs(angularVelocity) < MIN_INERTIA_VELOCITY) {
            angularVelocity = 0
            inertiaFrame = undefined
            return
        }

        coinRotation.value += angularVelocity
        inertiaFrame = requestAnimationFrame(animate)
    }

    inertiaFrame = requestAnimationFrame(animate)
}

onBeforeUnmount(stopInertia)

watch(() => props.isGameEnded, (isEnded) => {
    if (!isEnded) return
    activePointerId = null
    clockwiseAngle = 0
    angularVelocity = 0
    stopInertia()
})
</script>

<template>
    <div class="h5-page game-stage">
        <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="rank-content">
            <div>
                实时得分
            </div>
            <div>
                {{ tick }}
            </div>
            <!-- <div class="txt-left">
                <div>排名</div>
                <div class="txt-bold"></div>
            </div>
            <div class="txt-right">
                <div>实时得分</div>
                <div class="txt-bold">{{ tick }}</div>
            </div> -->
        </div>
        <div class="img-pointer"></div>
        <div ref="coinRef" class="img-coin" :style="{ '--coin-rotation': `${coinRotation}deg` }"
            @pointerdown="startRotation" @pointermove="rotateCoin" @pointerup="stopRotation"
            @pointercancel="stopRotation"></div>
        <!-- <div class="img-process">
            <div class="txt-process">{{ score }}</div>
            <div class="img-coin-icon"></div>
        </div> -->
    </div>
</template>

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


.div-desc {
    position: absolute;
    top: 150px;
    left: var(--stage-viewport-left, 0);
    z-index: 2;
    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;
    }
}

.rank-content {
    width: 600px;
    height: 140px;
    border: 1px solid #A10A06;
    border-radius: 25px;
    background: #F7DA81;
    /* background: v-bind('imageUrls.rank') center/cover; */
    position: absolute;
    left: 50%;
    top: 570px;
    display: flex;
    /* align-items: center;
    justify-content: space-between; */
    transform: translate(-50%, -50%);
    font-size: 44px;
    color: #A10A06;

    .txt-bold {
        font-size: 40px;
        font-weight: bold;
    }

    >div {
        display: flex;
        width: 50%;
        height: 100%;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }
}

.img-pointer {
    width: 354px;
    height: 354px;
    background: v-bind('imageUrls.point');
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: 141px;
    margin-top: -9px;
    z-index: 9;
    transform: scale(0.9);
}

/* 
.txt-tick {
    position: absolute;
    left: 500px;
    top: 267px;
    font-size: 70px;
    font-weight: bold;
    color: #BF1D19;
} */

.img-coin {
    background: v-bind('imageUrls.coin') center / cover no-repeat;
    width: 744px;
    height: 756px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) scale(0.6) rotate(var(--coin-rotation, 0deg));
    transform-origin: center;
    touch-action: none;
    user-select: none;
    cursor: grab;
    will-change: transform;
    margin-top: 70px;
}

.img-coin:active {
    cursor: grabbing;
}

/* .img-process {
    background: v-bind('imageUrls.process') center / cover no-repeat;
    width: 662px;
    height: 82px;
    position: absolute;
    bottom: 110px;
    left: 50%;
    transform: translateX(-50%);

    .txt-process {
        font-size: 30px;
        width: 100%;
        text-align: center;
        position: absolute;
        top: 38px;
        color: white;
        font-weight: bold;
    }
}

.img-coin-icon {
    background: v-bind('imageUrls.coinIcon') center / cover no-repeat;
    width: 132px;
    height: 67px;
    position: absolute;
    top: -10px;
} */
</style>
