<template>
    <view class="page" :style="rootStyle">
        <!-- ===== 主舞台:节拍器圆 ===== -->
        <view class="stage" @click="togglePlay">
            <view class="ring r1" :class="{ playing: isPlaying }" />
            <view class="ring r2" :class="{ playing: isPlaying }" />
            <view class="core" :class="{ playing: isPlaying, accent: isAccent }">
                <text class="bpm-num">{{ bpm }}</text>
                <text class="bpm-label">BPM</text>
                <view class="ctrl">
                    <view v-if="isPlaying" class="icon-pause">
                        <view class="bar" />
                        <view class="bar" />
                    </view>
                    <view v-else class="icon-play" />
                </view>
            </view>
        </view>

        <!-- ===== 配速 + 走路动画卡片 ===== -->
        <view class="walker-card">
            <view class="walker-header">
                <view class="badge" :class="badgeClass">
                    <view class="badge-dot" />
                    <text>{{ walkerTip }}</text>
                </view>
                <text class="status">{{ statusHint }}</text>
            </view>

            <view class="walker" :class="{ playing: isPlaying }">
                <view class="runner-card">
                    <video
                        id="runner-video"
                        class="runner-video"
                        src="/static/training/runner.mp4"
                        :muted="true"
                        :loop="true"
                        :autoplay="true"
                        :show-controls="false"
                        :show-fullscreen-btn="false"
                        :show-play-btn="false"
                        :show-center-play-btn="false"
                        :enable-progress-gesture="false"
                        :show-mute-btn="false"
                        object-fit="contain"
                        @error="onVideoError"
                        @loadedmetadata="onVideoLoaded"
                    />
                </view>
            </view>
        </view>

        <!-- ===== 控制卡片:BPM + 拍号 ===== -->
        <view class="control-card">
            <view class="bpm-row">
                <view class="step-btn" @click="adjustBpm(-10)">
                    <text class="step-num">−10</text>
                </view>
                <view class="step-btn" @click="adjustBpm(-1)">
                    <text class="step-num">−1</text>
                </view>
                <view class="step-btn" @click="adjustBpm(1)">
                    <text class="step-num">+1</text>
                </view>
                <view class="step-btn" @click="adjustBpm(10)">
                    <text class="step-num">+10</text>
                </view>
            </view>

            <view class="divider" />

            <view class="meter-row">
                <text class="meter-label">每组拍数</text>
                <view class="meter-options">
                    <view
                        v-for="m in METER_OPTIONS"
                        :key="m.value"
                        class="meter-btn"
                        :class="{ active: accentEvery === m.value }"
                        @click="onMeterChange(m.value)"
                    >
                        <text>{{ m.label }}</text>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { onShow, onHide } from '@dcloudio/uni-app'
import { useMetronome } from '@/hooks/useMetronome'

/**
 * 视频原速对应的 BPM 基准
 * runner.mp4 时长 0.97s, 一个 walk cycle (左右脚各一次) ≈ 124 BPM 步频
 * 用户调速时 playbackRate = bpm / VIDEO_BASE_BPM
 * 微信小程序限制 playback-rate 范围 [0.5, 2.0]
 */
const VIDEO_BASE_BPM = 124

const METER_OPTIONS = [
    { label: '2', value: 2 },
    { label: '3', value: 3 },
    { label: '4', value: 4 },
]

const metronome = useMetronome({
    initialBpm: 80,
    accentEvery: 4,
    clickSrc: '/static/training/audio/click.mp3',
    accentSrc: '/static/training/audio/click-wood.mp3',
})
const {
    bpm,
    isPlaying,
    beatIndex,
    isAccent,
    accentEvery,
    intervalMs,
    start,
    stop,
    setBpm,
    setAccentEvery,
    preload,
} = metronome

const adjustBpm = (delta: number) => {
    setBpm(bpm.value + delta)
}

const onMeterChange = (val: number) => {
    setAccentEvery(val)
}

const togglePlay = () => {
    if (isPlaying.value) {
        stop()
        uni.setKeepScreenOn({ keepScreenOn: false })
    } else {
        start()
        uni.setKeepScreenOn({ keepScreenOn: true })
    }
}

/* 视频实例与 BPM 同步 */
let videoCtx: UniApp.VideoContext | null = null

const playbackRate = computed(() => {
    const rate = bpm.value / VIDEO_BASE_BPM
    return Math.max(0.5, Math.min(2.0, +rate.toFixed(2)))
})

onMounted(() => {
    videoCtx = uni.createVideoContext('runner-video')
    /* 进页面默认让视频保持暂停,跟节拍器 isPlaying 状态同步 */
    setTimeout(() => videoCtx?.pause(), 50)
})

const onVideoError = (e: any) => {
    console.error('[runner-video] error:', e?.detail || e)
    uni.showToast({
        title: '视频加载失败,请用真机预览',
        icon: 'none',
        duration: 2500,
    })
}

const onVideoLoaded = (e: any) => {
    console.log('[runner-video] metadata loaded:', e?.detail)
    /* 元数据加载完后再设 playbackRate,部分基础库初始化时设非 1.0 会卡 */
    try {
        videoCtx?.playbackRate?.(playbackRate.value)
    } catch (_) {}
}

/* 节拍器状态变化 → 同步视频播放/暂停 */
watch(isPlaying, (playing) => {
    if (playing) {
        videoCtx?.play()
    } else {
        videoCtx?.pause()
    }
})

/* BPM 变化 → 调整视频播放速度(部分基础库需要手动 API 调用) */
watch(playbackRate, (rate) => {
    try {
        videoCtx?.playbackRate?.(rate)
    } catch (_) {}
})

const rootStyle = computed(() => ({
    '--beat-duration': `${intervalMs.value}ms`,
    '--step-duration': `${intervalMs.value}ms`,
}))

const statusHint = computed(() => {
    if (isPlaying.value) {
        const cur = ((beatIndex.value - 1) % accentEvery.value) + 1
        return `第 ${cur} 拍 / 共 ${accentEvery.value} 拍`
    }
    return '轻点中央圆点开始'
})

const walkerTip = computed(() => {
    if (bpm.value < 70) return '慢走 · 热身'
    if (bpm.value < 100) return '健走 · 日常'
    if (bpm.value < 130) return '快走 · 提速'
    if (bpm.value < 170) return '慢跑 · 有氧'
    return '快跑 · 高强'
})

const badgeClass = computed(() => {
    if (bpm.value < 100) return 'badge-mild'
    if (bpm.value < 130) return 'badge-mid'
    if (bpm.value < 170) return 'badge-strong'
    return 'badge-hot'
})

onShow(() => {
    preload()
})

onHide(() => {
    if (isPlaying.value) {
        stop()
        uni.setKeepScreenOn({ keepScreenOn: false })
    }
})

onUnmounted(() => {
    uni.setKeepScreenOn({ keepScreenOn: false })
})
</script>

<style lang="scss" scoped>
/* ============================================================
 * 设计 token
 * ============================================================ */
$bg-grad: linear-gradient(180deg, #0a0f1c 0%, #141a2a 100%);
$card-bg: rgba(255, 255, 255, 0.035);
$card-border: rgba(255, 255, 255, 0.06);
$text-1: #f1f5f9;
$text-2: #cbd5e1;
$text-3: #64748b;
$brand: #22c55e;
$brand-deep: #15803d;
$accent: #f59e0b;
$accent-deep: #b45309;
$radius-card: 28rpx;
$radius-btn: 20rpx;

/* ============================================================
 * 页面容器
 * ============================================================ */
.page {
    height: 100vh;
    box-sizing: border-box;
    padding: 30rpx 28rpx 60rpx;
    background: $bg-grad;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 24rpx;
    color: $text-1;
    overflow: hidden;
}

/* ============================================================
 * 节拍器主舞台
 * ============================================================ */
.stage {
    position: relative;
    width: 540rpx;
    height: 540rpx;
    margin-top: 20rpx;
    display: flex;
    align-items: center;
    justify-content: center;

    &:active .core {
        transform: scale(0.97);
    }
}

.ring {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 3rpx solid rgba(34, 197, 94, 0.14);
    pointer-events: none;

    &.playing {
        animation: ring-pulse var(--beat-duration, 750ms) ease-out infinite;
    }
    &.r2.playing {
        animation-delay: calc(var(--beat-duration, 750ms) * -0.5);
    }
}
@keyframes ring-pulse {
    0% {
        transform: scale(0.94);
        opacity: 0.85;
        border-color: rgba(34, 197, 94, 0.45);
    }
    100% {
        transform: scale(1.18);
        opacity: 0;
        border-color: rgba(34, 197, 94, 0);
    }
}

.core {
    position: relative;
    width: 420rpx;
    height: 420rpx;
    border-radius: 50%;
    background: linear-gradient(140deg, $brand 0%, $brand-deep 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    box-shadow:
        inset 0 -16rpx 50rpx rgba(0, 0, 0, 0.22),
        inset 0 16rpx 50rpx rgba(255, 255, 255, 0.1),
        0 20rpx 50rpx rgba(34, 197, 94, 0.32);
    transition: transform 0.12s, background 0.18s, box-shadow 0.18s;

    &.playing {
        animation: core-beat var(--beat-duration, 750ms) ease-in-out infinite;
    }

    &.playing.accent {
        background: linear-gradient(140deg, #fbbf24 0%, $accent-deep 100%);
        box-shadow:
            inset 0 -16rpx 50rpx rgba(0, 0, 0, 0.22),
            inset 0 16rpx 50rpx rgba(255, 255, 255, 0.18),
            0 20rpx 50rpx rgba(245, 158, 11, 0.4);
    }

    .bpm-num {
        font-size: 180rpx;
        font-weight: 800;
        color: #fff;
        line-height: 1;
        letter-spacing: -2rpx;
        font-variant-numeric: tabular-nums;
        text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.18);
    }

    .bpm-label {
        font-size: 22rpx;
        color: rgba(255, 255, 255, 0.65);
        letter-spacing: 6rpx;
        margin-top: 10rpx;
        font-weight: 600;
    }

    .ctrl {
        margin-top: 26rpx;
        height: 76rpx;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}
@keyframes core-beat {
    0%,
    100% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.04);
    }
}

/* 播放/暂停 icon (CSS 几何) */
.icon-play {
    width: 0;
    height: 0;
    border-left: 60rpx solid #fff;
    border-top: 38rpx solid transparent;
    border-bottom: 38rpx solid transparent;
    margin-left: 14rpx;
    filter: drop-shadow(0 2rpx 6rpx rgba(0, 0, 0, 0.2));
}
.icon-pause {
    display: flex;
    gap: 18rpx;
    height: 70rpx;

    .bar {
        width: 18rpx;
        height: 100%;
        background: #fff;
        border-radius: 5rpx;
        box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.2);
    }
}

/* ============================================================
 * 走路动画卡片
 * ============================================================ */
.walker-card {
    width: 100%;
    background: $card-bg;
    border: 1rpx solid $card-border;
    border-radius: $radius-card;
    padding: 24rpx 28rpx 32rpx;
    backdrop-filter: blur(20rpx);
}

.walker-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12rpx;
}

.badge {
    display: flex;
    align-items: center;
    gap: 10rpx;
    padding: 8rpx 20rpx;
    background: rgba(34, 197, 94, 0.12);
    border: 1rpx solid rgba(34, 197, 94, 0.3);
    border-radius: 999rpx;
    font-size: 24rpx;
    color: $brand;
    font-weight: 600;

    .badge-dot {
        width: 12rpx;
        height: 12rpx;
        border-radius: 50%;
        background: currentColor;
        box-shadow: 0 0 8rpx currentColor;
    }

    &.badge-mild {
        background: rgba(34, 197, 94, 0.12);
        border-color: rgba(34, 197, 94, 0.3);
        color: #4ade80;
    }
    &.badge-mid {
        background: rgba(251, 191, 36, 0.12);
        border-color: rgba(251, 191, 36, 0.3);
        color: #fbbf24;
    }
    &.badge-strong {
        background: rgba(249, 115, 22, 0.12);
        border-color: rgba(249, 115, 22, 0.3);
        color: #fb923c;
    }
    &.badge-hot {
        background: rgba(239, 68, 68, 0.14);
        border-color: rgba(239, 68, 68, 0.32);
        color: #f87171;
    }
}

.status {
    font-size: 24rpx;
    color: $text-3;
    letter-spacing: 1rpx;
}

.walker {
    position: relative;
    width: 100%;
    height: 240rpx;
    display: flex;
    justify-content: center;
    align-items: flex-end;
}

/* ============================================================
 * 跑步小人视频(白卡嵌入)
 * ============================================================ */
.runner-card {
    position: absolute;
    bottom: 18rpx;
    left: 50%;
    transform: translateX(-50%);
    width: 220rpx;
    height: 220rpx;
    background: #fff;
    border-radius: 32rpx;
    overflow: hidden;
    box-shadow:
        0 12rpx 32rpx rgba(0, 0, 0, 0.25),
        inset 0 0 0 1rpx rgba(255, 255, 255, 0.3);
}

.runner-video {
    width: 100%;
    height: 100%;
    background: #fff;
}

/* ============================================================
 * 控制卡片(BPM + 拍号)
 * ============================================================ */
.control-card {
    width: 100%;
    background: $card-bg;
    border: 1rpx solid $card-border;
    border-radius: $radius-card;
    padding: 28rpx;
    backdrop-filter: blur(20rpx);
}

.bpm-row {
    display: flex;
    gap: 14rpx;
}

.step-btn {
    flex: 1;
    height: 96rpx;
    border-radius: $radius-btn;
    background: rgba(255, 255, 255, 0.05);
    border: 1rpx solid rgba(255, 255, 255, 0.08);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;

    &:active {
        background: rgba(34, 197, 94, 0.18);
        border-color: rgba(34, 197, 94, 0.5);
        transform: scale(0.96);
    }

    .step-num {
        font-size: 38rpx;
        color: $text-1;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        letter-spacing: -1rpx;
    }
}

.divider {
    height: 1rpx;
    background: rgba(255, 255, 255, 0.06);
    margin: 24rpx 0;
}

.meter-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20rpx;
}

.meter-label {
    font-size: 26rpx;
    color: $text-3;
    letter-spacing: 1rpx;
}

.meter-options {
    display: flex;
    gap: 10rpx;
    background: rgba(255, 255, 255, 0.04);
    padding: 6rpx;
    border-radius: 999rpx;
    border: 1rpx solid rgba(255, 255, 255, 0.05);
}

.meter-btn {
    min-width: 84rpx;
    height: 60rpx;
    padding: 0 20rpx;
    border-radius: 999rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.18s;

    text {
        font-size: 30rpx;
        color: $text-2;
        font-weight: 600;
    }

    &.active {
        background: $brand;
        box-shadow: 0 4rpx 12rpx rgba(34, 197, 94, 0.4);

        text {
            color: #fff;
        }
    }
}
</style>
