<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
import AddSongModal from './components/AddSongModal.vue'
import { addSong, deleteSong, moveSong, youtubeSearchUrl, type Song } from './logic/playlist'
import { loadState, saveState } from './logic/storage'

const playlist = ref<Song[]>([])
const showAdd = ref(false)
const pendingDeletes = ref<Record<number, number>>({}) // songId -> timeoutId
const DELETE_DELAY_MS = 10_000

onMounted(() => {
  playlist.value = loadState().playlist
})

watch(playlist, () => saveState({ playlist: playlist.value }), { deep: true })

onUnmounted(() => {
  for (const id of Object.values(pendingDeletes.value)) clearTimeout(id)
})

function onAdd(payload: { singer: string; title: string }) {
  playlist.value = addSong(playlist.value, payload.singer, payload.title)
  showAdd.value = false
}

function onMove(songId: number, direction: 'up' | 'down' | 'first') {
  playlist.value = moveSong(playlist.value, songId, direction)
}

function startDelete(songId: number) {
  pendingDeletes.value[songId] = window.setTimeout(() => {
    playlist.value = deleteSong(playlist.value, songId)
    delete pendingDeletes.value[songId]
  }, DELETE_DELAY_MS)
}

function cancelDelete(songId: number) {
  const t = pendingDeletes.value[songId]
  if (t !== undefined) {
    clearTimeout(t)
    delete pendingDeletes.value[songId]
  }
}

function isPending(songId: number): boolean {
  return pendingDeletes.value[songId] !== undefined
}
</script>

<template>
  <main>
    <header class="topbar">
      <h1>🎤 Karaoke 点歌</h1>
      <button class="primary" @click="showAdd = true">+ 添加歌曲</button>
    </header>

    <section v-if="playlist.length === 0" class="empty">
      <p>点歌单空空如也</p>
      <p class="dim">点击 "添加歌曲" 把歌排进队</p>
    </section>

    <section v-else class="list">
      <article
        v-for="(song, idx) in playlist"
        :key="song.id"
        :class="['item', { pending: isPending(song.id) }]"
      >
        <div class="meta">
          <span class="idx">{{ idx + 1 }}</span>
          <div class="text">
            <div class="title">{{ song.title }}</div>
            <div class="singer">{{ song.singer }}</div>
          </div>
        </div>
        <div class="actions">
          <a
            :href="youtubeSearchUrl(song)"
            target="_blank"
            rel="noopener noreferrer"
            class="action yt"
            title="在 YouTube 搜索"
          >YT</a>
          <button class="action" :disabled="idx === 0 || isPending(song.id)" @click="onMove(song.id, 'first')" title="置顶">⇈</button>
          <button class="action" :disabled="idx === 0 || isPending(song.id)" @click="onMove(song.id, 'up')" title="上移">↑</button>
          <button class="action" :disabled="idx === playlist.length - 1 || isPending(song.id)" @click="onMove(song.id, 'down')" title="下移">↓</button>
          <button v-if="!isPending(song.id)" class="action danger" @click="startDelete(song.id)" title="删除">✕</button>
          <button v-else class="action cancel-delete" @click="cancelDelete(song.id)">撤销</button>
        </div>
        <div v-if="isPending(song.id)" class="progress">
          <div class="bar" />
        </div>
      </article>
    </section>

    <AddSongModal :show="showAdd" @close="showAdd = false" @add="onAdd" />
  </main>
</template>

<style scoped>
main {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 16px 40px;
}
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
h1 { margin: 0; font-size: 1.5rem; background: linear-gradient(135deg, #fff, var(--accent)); -webkit-background-clip: text; background-clip: text; color: transparent; }
button.primary { background: var(--accent); border: none; color: white; padding: 10px 16px; border-radius: 8px; font-weight: bold; }

.empty {
  text-align: center;
  background: var(--bg-soft);
  border-radius: 12px;
  padding: 60px 20px;
  color: var(--fg-dim);
}
.empty .dim { font-size: 0.9rem; opacity: 0.7; margin-top: 6px; }

.list { display: flex; flex-direction: column; gap: 8px; }
.item {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.item.pending { opacity: 0.55; background: rgba(239, 68, 68, 0.1); }
.meta { display: flex; align-items: center; gap: 12px; min-width: 0; }
.idx {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(236, 72, 153, 0.2);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 0.85rem;
}
.text { min-width: 0; flex: 1; }
.title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.singer { color: var(--fg-dim); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.actions { display: flex; gap: 6px; flex-wrap: wrap; }
.action {
  min-width: 36px;
  height: 36px;
  border: 1px solid var(--border);
  background: var(--bg-soft);
  color: var(--fg);
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  padding: 0 8px;
  text-decoration: none;
  font-size: 0.9rem;
}
.action.yt { color: #ff4d4d; }
.action.danger { color: var(--danger); border-color: rgba(239, 68, 68, 0.4); }
.action.cancel-delete { background: var(--accent-2); border-color: var(--accent-2); color: #000; font-size: 0.8rem; }
.progress { height: 3px; background: rgba(239, 68, 68, 0.2); border-radius: 2px; overflow: hidden; }
.bar {
  height: 100%;
  background: var(--danger);
  animation: shrink 10s linear forwards;
}
@keyframes shrink { from { width: 100%; } to { width: 0; } }

@media (max-width: 500px) {
  .actions { gap: 4px; }
  .action { min-width: 32px; height: 32px; font-size: 0.85rem; }
}
</style>
