<template>
    <view class="page" :style="rootStyle">
        <!-- ===== 主舞台:节拍器圆 ===== -->
        <view class="stage" @click="onCenterTap">
            <view class="ring r1" :class="{ playing: isPlaying }" />
            <view class="ring r2" :class="{ playing: isPlaying }" />
            <view class="core" :class="{ playing: isPlaying }">
                <text class="bpm-num">{{ currentBpm }}</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">
            <view class="walker-box">
                <video
                    id="runner-video"
                    class="runner-video"
                    :src="RUNNER_VIDEO_URL"
                    :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"
                    :picture-in-picture-mode="[]"
                    object-fit="contain"
                    @error="onVideoError"
                    @loadedmetadata="onVideoLoaded"
                />
                <!-- #ifdef MP-WEIXIN -->
                <cover-view class="pip-mask">&nbsp;</cover-view>
                <!-- #endif -->
            </view>
        </view>

        <!-- ===== 推荐档位(3 选 1) ===== -->
        <view class="presets">
            <view
                v-for="p in LOOP_PRESETS"
                :key="p.id"
                class="preset"
                :class="{ active: mode === 'preset' && currentLoop === p.id }"
                @click="onPresetTap(p.id)"
            >
                <text class="preset-icon">{{ presetIcon(p.id) }}</text>
                <text class="preset-name">{{ presetName(p.id) }}</text>
                <text class="preset-bpm">{{ p.bpm }} BPM</text>
                <text class="preset-desc">{{ presetDesc(p.id) }}</text>
            </view>
        </view>

        <!-- ===== 自定义节奏(高级折叠区) ===== -->
        <view v-if="customExpanded" class="custom-panel">
            <view class="custom-warn">
                <text class="warn-dot">●</text>
                <text class="warn-text">前台模式 · 切后台会暂停</text>
            </view>

            <!-- BPM 微调 -->
            <view class="row">
                <text class="row-label">BPM</text>
                <view class="bpm-stepper">
                    <view class="step-btn" @click="onBpmDelta(-5)">−5</view>
                    <view class="step-btn" @click="onBpmDelta(-1)">−1</view>
                    <view class="step-val">{{ customBpm }}</view>
                    <view class="step-btn" @click="onBpmDelta(1)">+1</view>
                    <view class="step-btn" @click="onBpmDelta(5)">+5</view>
                </view>
            </view>

            <!-- 拍号 -->
            <view class="row">
                <text class="row-label">拍号</text>
                <view class="meter-tabs">
                    <view
                        v-for="n in [2, 3, 4]"
                        :key="n"
                        class="meter-tab"
                        :class="{ active: customAccent === n }"
                        @click="onAccentSelect(n)"
                    >{{ n }}/4</view>
                </view>
            </view>
        </view>

        <!-- 底部行:自定义入口 + 提示 -->
        <view class="bottom-row">
            <text class="bottom-link" @click="onToggleCustom">
                {{ customExpanded ? '✕ 收起自定义' : '⚙ 自定义节奏' }}
            </text>
            <text class="bottom-hint" v-if="mode === 'preset'">🔒 锁屏可继续播放</text>
        </view>
    </view>
</template>

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

/**
 * 跑步动画视频(腾讯云 COS CDN)
 * 注意:小程序后台需将 cos.ap-guangzhou.myqcloud.com 加入 downloadFile 合法域名,
 *       否则正式发布版会被拦截(开发版默认不校验)
 */
const RUNNER_VIDEO_URL =
    'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/video/20260525/20260525164014ef89f8862.mp4'

/** 视频原速对应的 BPM 基准, playback-rate 范围 [0.5, 2.0] */
const VIDEO_BASE_BPM = 124

/* ============================================================
 * 双引擎设计
 * ------------------------------------------------------------
 * - mode='preset': 用 BgAudio 播预合成 mp3,支持后台/锁屏(走路场景)
 * - mode='custom': 用 InnerAudio 实时合成,支持任意 BPM/拍号,但仅前台
 * - 切模式时停掉对侧引擎,避免双声道叠加
 * ============================================================ */
type Mode = 'preset' | 'custom'
const mode = ref<Mode>('preset')
const customExpanded = ref<boolean>(false)

/* click-wood.mp3 (CDN), 木鱼质感的敲击音 */
const CLICK_WOOD_URL =
    'https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/202605261051282a0a94508.mp3'

const bg = useMetronomeBg()
const fg = useMetronome({
    initialBpm: 100,
    accentEvery: 2,
    clickSrc: CLICK_WOOD_URL,
    accentSrc: CLICK_WOOD_URL,
    poolSize: 4,
})

const { LOOP_PRESETS } = bg
const currentLoop = bg.currentLoop

const customBpm = computed(() => fg.bpm.value)
const customAccent = computed(() => fg.accentEvery.value)

/* 统一对外暴露的 isPlaying / currentBpm,根据 mode 选择信号源 */
const isPlaying = computed(() =>
    mode.value === 'preset' ? bg.isPlaying.value : fg.isPlaying.value,
)

const currentBpm = computed(() => {
    if (mode.value === 'preset') {
        const p = LOOP_PRESETS.find((p) => p.id === currentLoop.value)
        return p?.bpm ?? 110
    }
    return fg.bpm.value
})

const intervalMs = computed(() => 60000 / currentBpm.value)

/* ============================================================
 * 档位元数据
 * ============================================================ */
const presetIcon = (id: LoopId) =>
    id === 'slow' ? '🚶' : id === 'normal' ? '🏃‍♀️' : '🏃'
const presetName = (id: LoopId) =>
    id === 'slow' ? '慢走' : id === 'normal' ? '健走' : '快走'
const presetDesc = (id: LoopId) =>
    id === 'slow' ? '热身 · 恢复' : id === 'normal' ? '日常 · 通勤' : '提速 · 燃脂'

/* ============================================================
 * 中央圆按钮:在两个模式下分别工作
 * ============================================================ */
const onCenterTap = () => {
    if (mode.value === 'preset') {
        if (!currentLoop.value) {
            bg.playLoop('normal')
            uni.setKeepScreenOn({ keepScreenOn: true })
            return
        }
        if (bg.isPlaying.value) {
            bg.pause()
            uni.setKeepScreenOn({ keepScreenOn: false })
        } else {
            bg.resume()
            uni.setKeepScreenOn({ keepScreenOn: true })
        }
    } else {
        /* custom 模式 */
        if (fg.isPlaying.value) {
            fg.stop()
            uni.setKeepScreenOn({ keepScreenOn: false })
        } else {
            fg.start()
            uni.setKeepScreenOn({ keepScreenOn: true })
        }
    }
}

/* ============================================================
 * 档位卡片:点了 → 切回 preset 模式 + 停掉 custom
 * ============================================================ */
const onPresetTap = (id: LoopId) => {
    if (mode.value === 'custom') {
        fg.stop()
        mode.value = 'preset'
        customExpanded.value = false
    }
    bg.playLoop(id)
    uni.setKeepScreenOn({ keepScreenOn: true })
}

/* ============================================================
 * 自定义折叠区切换
 * ============================================================ */
const onToggleCustom = () => {
    if (!customExpanded.value) {
        /* 展开:进入 custom 模式 + 停掉 preset */
        if (bg.isPlaying.value || currentLoop.value) {
            bg.stop()
        }
        mode.value = 'custom'
        /* 把当前显示 BPM 带过去当起始值 */
        const seed =
            LOOP_PRESETS.find((p) => p.id === (currentLoop.value ?? 'normal'))?.bpm ?? 100
        fg.setBpm(seed)
        fg.setAccentEvery(2)
        /* 立即预热 InnerAudio,避免首拍冷启动延迟 */
        fg.preload()
        customExpanded.value = true
    } else {
        /* 收起:回到 preset,停掉 fg */
        fg.stop()
        mode.value = 'preset'
        customExpanded.value = false
        uni.setKeepScreenOn({ keepScreenOn: false })
    }
}

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

const onAccentSelect = (n: number) => {
    fg.setAccentEvery(n)
}

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

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

onMounted(() => {
    videoCtx = uni.createVideoContext('runner-video')
    setTimeout(() => videoCtx?.pause(), 50)
})

const onVideoError = (e: any) => {
    console.error('[runner-video] error:', e?.detail || e)
}

const onVideoLoaded = (e: any) => {
    console.log('[runner-video] metadata loaded:', e?.detail)
    try {
        videoCtx?.playbackRate?.(playbackRate.value)
    } catch (_) {}
}

watch(isPlaying, (playing) => {
    if (playing) {
        videoCtx?.play()
    } else {
        videoCtx?.pause()
    }
})

watch(playbackRate, (rate) => {
    try {
        videoCtx?.playbackRate?.(rate)
    } catch (_) {}
})

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

onShow(() => {
    /* custom 模式回到前台时主动预加载,避免冷启动延迟 */
    if (mode.value === 'custom') {
        fg.preload()
    }
})

/**
 * onHide:差异化处理
 *   - preset 模式: 不停,BgAudio 接管后台播放
 *   - custom 模式: 立即停掉,InnerAudio 后台不工作,留着会被 iOS 挂起后状态错乱
 */
onHide(() => {
    if (mode.value === 'custom') {
        fg.stop()
        uni.setKeepScreenOn({ keepScreenOn: false })
    }
})

onUnmounted(() => {
    /* 页面销毁时全部清理 */
    if (mode.value === 'preset' && bg.isPlaying.value) bg.stop()
    if (mode.value === 'custom') fg.stop()
    uni.setKeepScreenOn({ keepScreenOn: false })
})
</script>

<style lang="scss" scoped>
/* ============================================================
 * 设计 token —— 浅色清爽
 * ============================================================ */
$bg-color: #f8fafc;
$card-bg: #ffffff;
$card-border: rgba(15, 23, 42, 0.06);
$text-1: #0f172a;
$text-2: #475569;
$text-3: #94a3b8;
$brand: #10b981;
$brand-soft: #d1fae5;
$brand-deep: #047857;
$warn: #f59e0b;
$warn-soft: #fef3c7;
$radius-card: 24rpx;
$shadow-sm: 0 4rpx 12rpx rgba(15, 23, 42, 0.04);

/* ============================================================
 * 页面容器
 * ============================================================ */
.page {
    position: relative;
    min-height: 100vh;
    box-sizing: border-box;
    padding: 30rpx 28rpx 50rpx;
    background: $bg-color;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20rpx;
    color: $text-1;
}

/* ============================================================
 * 节拍器主舞台
 * ============================================================ */
.stage {
    position: relative;
    width: 480rpx;
    height: 480rpx;
    margin-top: 12rpx;
    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(16, 185, 129, 0.12);
    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(16, 185, 129, 0.4);
    }
    100% {
        transform: scale(1.18);
        opacity: 0;
        border-color: rgba(16, 185, 129, 0);
    }
}

.core {
    position: relative;
    width: 380rpx;
    height: 380rpx;
    border-radius: 50%;
    background: linear-gradient(140deg, #34d399 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.18),
        inset 0 16rpx 50rpx rgba(255, 255, 255, 0.18),
        0 16rpx 40rpx rgba(16, 185, 129, 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;
    }

    .bpm-num {
        font-size: 168rpx;
        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.16);
    }

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

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

/* 播放/暂停 icon */
.icon-play {
    width: 0;
    height: 0;
    border-left: 52rpx solid #fff;
    border-top: 32rpx solid transparent;
    border-bottom: 32rpx solid transparent;
    margin-left: 12rpx;
    filter: drop-shadow(0 2rpx 6rpx rgba(0, 0, 0, 0.18));
}
.icon-pause {
    display: flex;
    gap: 16rpx;
    height: 60rpx;

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

/* ============================================================
 * 跑步小人
 * ============================================================ */
.walker {
    width: 100%;
    height: 240rpx;
    display: flex;
    justify-content: center;
    align-items: center;
}

.walker-box {
    position: relative;
    width: 240rpx;
    height: 240rpx;
    background: #e8ecf2;
    border-radius: 24rpx;
    overflow: hidden;
    box-shadow: 0 4rpx 14rpx rgba(15, 23, 42, 0.06);
}

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

.pip-mask {
    position: absolute;
    top: 0;
    right: 0;
    width: 80rpx;
    height: 56rpx;
    background-color: #dde2eb;
    border-bottom-left-radius: 18rpx;
    border-top-right-radius: 24rpx;
}

/* ============================================================
 * 三档位推荐
 * ============================================================ */
.presets {
    width: 100%;
    display: flex;
    gap: 14rpx;
}

.preset {
    flex: 1;
    background: $card-bg;
    border: 2rpx solid $card-border;
    border-radius: $radius-card;
    padding: 18rpx 8rpx 16rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4rpx;
    box-shadow: $shadow-sm;
    transition: all 0.18s;

    .preset-icon {
        font-size: 40rpx;
        line-height: 1;
        margin-bottom: 4rpx;
    }
    .preset-name {
        font-size: 28rpx;
        font-weight: 700;
        color: $text-1;
        letter-spacing: 2rpx;
    }
    .preset-bpm {
        font-size: 22rpx;
        color: $text-2;
        font-weight: 600;
        font-variant-numeric: tabular-nums;
    }
    .preset-desc {
        font-size: 18rpx;
        color: $text-3;
        letter-spacing: 1rpx;
        margin-top: 2rpx;
    }

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

    &.active {
        background: $brand-soft;
        border-color: $brand;
        box-shadow:
            0 8rpx 20rpx rgba(16, 185, 129, 0.18),
            inset 0 0 0 2rpx rgba(16, 185, 129, 0.4);

        .preset-name {
            color: $brand-deep;
        }
        .preset-bpm {
            color: $brand-deep;
        }
        .preset-desc {
            color: $brand;
        }
    }
}

/* ============================================================
 * 自定义节奏面板(仅 customExpanded 时显示)
 * ============================================================ */
.custom-panel {
    width: 100%;
    background: $card-bg;
    border: 2rpx solid rgba(245, 158, 11, 0.25);
    border-radius: $radius-card;
    box-shadow: 0 6rpx 18rpx rgba(245, 158, 11, 0.08);
    padding: 20rpx 24rpx 22rpx;
    display: flex;
    flex-direction: column;
    gap: 16rpx;
}

.custom-warn {
    display: flex;
    align-items: center;
    gap: 8rpx;
    margin-bottom: 4rpx;

    .warn-dot {
        font-size: 18rpx;
        color: $warn;
    }
    .warn-text {
        font-size: 22rpx;
        color: #b45309;
        letter-spacing: 0.5rpx;
        font-weight: 600;
    }
}

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

    .row-label {
        font-size: 24rpx;
        color: $text-2;
        font-weight: 600;
        letter-spacing: 1rpx;
        flex-shrink: 0;
        width: 70rpx;
    }
}

.bpm-stepper {
    display: flex;
    align-items: center;
    gap: 6rpx;
    flex: 1;
    justify-content: flex-end;

    .step-btn {
        min-width: 56rpx;
        height: 52rpx;
        line-height: 52rpx;
        text-align: center;
        font-size: 22rpx;
        color: $text-2;
        background: #f1f5f9;
        border-radius: 10rpx;
        font-weight: 600;
        padding: 0 10rpx;
        font-variant-numeric: tabular-nums;

        &:active {
            background: #e2e8f0;
            transform: scale(0.94);
        }
    }
    .step-val {
        min-width: 84rpx;
        height: 52rpx;
        line-height: 52rpx;
        text-align: center;
        font-size: 30rpx;
        font-weight: 800;
        color: $text-1;
        font-variant-numeric: tabular-nums;
        background: $warn-soft;
        border-radius: 10rpx;
    }
}

.meter-tabs {
    display: flex;
    gap: 8rpx;

    .meter-tab {
        height: 52rpx;
        line-height: 52rpx;
        padding: 0 18rpx;
        font-size: 22rpx;
        color: $text-2;
        background: #f1f5f9;
        border-radius: 10rpx;
        font-weight: 600;
        letter-spacing: 1rpx;

        &.active {
            background: $warn;
            color: #fff;
            box-shadow: 0 4rpx 10rpx rgba(245, 158, 11, 0.3);
        }
        &:active {
            transform: scale(0.94);
        }
    }
}

/* ============================================================
 * 底部行(自定义入口 + 锁屏提示,横向排布)
 * ============================================================ */
.bottom-row {
    width: 100%;
    margin-top: 6rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 6rpx;
}

.bottom-link {
    font-size: 22rpx;
    color: $text-3;
    letter-spacing: 0.5rpx;
    padding: 8rpx 4rpx;

    &:active {
        color: $text-2;
    }
}

.bottom-hint {
    font-size: 22rpx;
    color: $text-3;
    letter-spacing: 0.5rpx;
}
</style>
