<template>
  <el-card shadow="never" class="playback-card">
    <template #header>
      <div class="pb-header">
        <div class="pb-title">
          <span>调度回放</span>
          <el-tag v-if="isPlaying" type="success" size="small" effect="dark" class="pb-playing">回放中</el-tag>
        </div>
        <div class="pb-actions">
          <el-input
            v-model="keyword"
            :prefix-icon="Search"
            placeholder="按名称 / 文件名 / 备注检索"
            clearable
            size="small"
            class="pb-search" />
          <el-button
            v-if="isPlaying"
            size="small"
            type="warning"
            plain
            :loading="stopping"
            @click="onStopPlayback">
            停止回放
          </el-button>
          <el-button size="small" :icon="Refresh" :loading="loading" @click="load">刷新</el-button>
        </div>
      </div>
    </template>

    <p v-if="recordingsDir" class="pb-dir">录像目录：{{ recordingsDir }}</p>

    <el-table :data="rows" v-loading="loading" stripe empty-text="暂无录像。在地图监控画布底栏「录制」后即可在此管理回放。">
      <el-table-column label="名称" min-width="220">
        <template #default="{ row }">
          <div class="pb-name">
            <span class="pb-name-text">{{ nameOf(row) }}</span>
            <el-tag v-if="!row.headerReadable" type="danger" size="small" effect="plain">头部不可读</el-tag>
          </div>
          <div v-if="row.displayName && row.displayName.trim()" class="pb-filename">{{ row.fileName }}</div>
        </template>
      </el-table-column>
      <el-table-column label="录制时间" width="180">
        <template #default="{ row }">{{ formatTime(row.fileWriteTime) }}</template>
      </el-table-column>
      <el-table-column label="时长" width="110" align="right">
        <template #default="{ row }">{{ formatDuration(row.durationMs) }}</template>
      </el-table-column>
      <el-table-column label="帧数" width="90" align="right">
        <template #default="{ row }">{{ row.frameCount || '-' }}</template>
      </el-table-column>
      <el-table-column label="大小" width="100" align="right">
        <template #default="{ row }">{{ formatSize(row.fileSizeBytes) }}</template>
      </el-table-column>
      <el-table-column prop="note" label="备注" min-width="140" show-overflow-tooltip />
      <el-table-column label="操作" width="220" fixed="right">
        <template #default="{ row }">
          <el-button
            text
            size="small"
            type="primary"
            :icon="VideoPlay"
            :disabled="!row.headerReadable"
            @click="onView(row)">
            查看
          </el-button>
          <el-button text size="small" type="danger" :icon="Delete" @click="onDelete(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-card>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { VideoPlay, Delete, Refresh, Search } from '@element-plus/icons-vue'
import { workspaceToolbarApi, type ToolbarRecordingEntry } from '@/api/workspaceToolbar'

const router = useRouter()

const loading = ref(false)
const stopping = ref(false)
const entries = ref<ToolbarRecordingEntry[]>([])
const recordingsDir = ref('')
const isPlaying = ref(false)
const keyword = ref('')

const rows = computed(() => {
  const kw = keyword.value.trim().toLowerCase()
  if (!kw) return entries.value
  return entries.value.filter(
    (e) =>
      (e.displayName || '').toLowerCase().includes(kw) ||
      e.fileName.toLowerCase().includes(kw) ||
      (e.note || '').toLowerCase().includes(kw)
  )
})

function nameOf(e: ToolbarRecordingEntry): string {
  return e.displayName && e.displayName.trim() ? e.displayName.trim() : e.fileName
}

function formatTime(s: string): string {
  if (!s) return '-'
  const d = new Date(s)
  return Number.isNaN(d.getTime()) ? s : d.toLocaleString()
}

function formatDuration(ms: number): string {
  if (!ms || ms < 0) return '-'
  const total = Math.round(ms / 1000)
  const h = Math.floor(total / 3600)
  const m = Math.floor((total % 3600) / 60)
  const s = total % 60
  const pad = (n: number) => String(n).padStart(2, '0')
  return h > 0 ? `${pad(h)}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`
}

function formatSize(bytes: number): string {
  if (!bytes || bytes < 0) return '-'
  if (bytes < 1024) return `${bytes} B`
  const kb = bytes / 1024
  if (kb < 1024) return `${kb < 10 ? kb.toFixed(1) : kb.toFixed(0)} KB`
  return `${(kb / 1024).toFixed(1)} MB`
}

async function load() {
  loading.value = true
  try {
    const state = await workspaceToolbarApi.getState()
    entries.value = state.recording?.entries ?? []
    recordingsDir.value = state.recording?.recordingsDirectory ?? ''
    isPlaying.value = !!state.recording?.isPlaying
  } catch (e) {
    entries.value = []
    ElMessage.error({ message: (e as Error).message || '加载录像列表失败', grouping: true })
  } finally {
    loading.value = false
  }
}

function onView(row: ToolbarRecordingEntry) {
  // 跳转地图监控并通过 ?playback= 触发回放；地图监控页在 webVRender iframe 就绪后调用
  // workspaceToolbarApi.startPlayback，SimpleLite 随即在该 iframe 终端弹出回放控制条。
  router.push({ path: '/admin/map-monitor', query: { playback: row.fileName } })
}

async function onDelete(row: ToolbarRecordingEntry) {
  try {
    await ElMessageBox.confirm(`确认删除录像「${nameOf(row)}」？此操作不可恢复。`, '删除录像', {
      type: 'warning',
      confirmButtonText: '删除',
      cancelButtonText: '取消'
    })
    await workspaceToolbarApi.deleteRecording(row.fileName)
    ElMessage.success('已删除')
    await load()
  } catch (e) {
    if (e === 'cancel' || e === 'close') return
    ElMessage.error(`删除失败：${(e as Error).message}`)
  }
}

async function onStopPlayback() {
  stopping.value = true
  try {
    await workspaceToolbarApi.stopPlayback()
    ElMessage.success('已停止回放')
    await load()
  } catch (e) {
    ElMessage.error(`停止回放失败：${(e as Error).message}`)
  } finally {
    stopping.value = false
  }
}

onMounted(load)
</script>

<style scoped>
.playback-card {
  height: 100%;
}
.pb-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.pb-title {
  display: flex;
  align-items: center;
  gap: 8px;
}
.pb-playing {
  font-weight: normal;
}
.pb-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.pb-search {
  width: 240px;
}
.pb-dir {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--mg-text-muted, #909399);
}
.pb-name {
  display: flex;
  align-items: center;
  gap: 8px;
}
.pb-name-text {
  font-weight: 500;
}
.pb-filename {
  font-size: 12px;
  color: var(--mg-text-muted, #909399);
}
</style>
