<template>
  <div class="canvas-toolbar">
    <!-- 对齐 -->
    <el-dropdown trigger="click" :hide-on-click="false" placement="top-start">
      <el-button size="small" :loading="busy.align">
        <el-icon><Operation /></el-icon>
        <span class="btn-label">对齐</span>
        <el-icon class="caret"><ArrowUp /></el-icon>
      </el-button>
      <template #dropdown>
        <el-dropdown-menu class="toolbar-menu">
          <div v-for="opt in ALIGN_OPTIONS" :key="opt.key" class="menu-row" @click.stop="toggleAlign(opt.key)">
            <el-checkbox :model-value="state?.align[opt.key] ?? false" />
            <span>{{ opt.label }}</span>
          </div>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

    <!-- 选择 -->
    <el-dropdown trigger="click" :hide-on-click="false" placement="top-start">
      <el-button size="small" :loading="busy.select">
        <el-icon><Pointer /></el-icon>
        <span class="btn-label">选择</span>
        <el-icon class="caret"><ArrowUp /></el-icon>
      </el-button>
      <template #dropdown>
        <el-dropdown-menu class="toolbar-menu">
          <div v-for="opt in SELECT_OPTIONS" :key="opt.key" class="menu-row" @click.stop="toggleSelect(opt.key)">
            <el-checkbox :model-value="state?.select[opt.key] ?? false" />
            <span>{{ opt.label }}</span>
          </div>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

    <!-- 右击功能 -->
    <el-dropdown trigger="click" placement="top-start">
      <el-button size="small">
        <el-icon><FirstAidKit /></el-icon>
        <span class="btn-label">右击功能</span>
        <el-icon class="caret"><ArrowUp /></el-icon>
      </el-button>
      <template #dropdown>
        <el-dropdown-menu class="toolbar-menu">
          <el-dropdown-item @click="onContextMenuPlaceholder">寻路</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

    <span class="separator" />

    <!-- 显示图层 -->
    <el-dropdown trigger="click" :hide-on-click="false" placement="top-start">
      <el-button size="small" :loading="busy.layer">
        <el-icon><Files /></el-icon>
        <span class="btn-label">显示图层</span>
        <el-icon class="caret"><ArrowUp /></el-icon>
      </el-button>
      <template #dropdown>
        <el-dropdown-menu class="toolbar-menu layer-menu">
          <div v-if="!state || state.layers.length === 0" class="menu-empty">（无图层）</div>
          <div
            v-else
            v-for="ly in state.layers"
            :key="ly.name"
            class="menu-row"
            @click.stop="toggleLayer(ly.name, !ly.visible)"
          >
            <el-checkbox :model-value="ly.visible" />
            <span>图层 {{ ly.name }}</span>
          </div>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

    <!-- 显示内容 -->
    <el-dropdown trigger="click" :hide-on-click="false" placement="top-start">
      <el-button size="small" :loading="busy.display">
        <el-icon><View /></el-icon>
        <span class="btn-label">显示内容</span>
        <el-icon class="caret"><ArrowUp /></el-icon>
      </el-button>
      <template #dropdown>
        <el-dropdown-menu class="toolbar-menu">
          <div v-for="opt in DISPLAY_OPTIONS" :key="opt.key" class="menu-row" @click.stop="toggleDisplay(opt.key)">
            <el-checkbox :model-value="state?.display[opt.key] ?? false" />
            <span>{{ opt.label }}</span>
          </div>
        </el-dropdown-menu>
      </template>
    </el-dropdown>

    <span class="separator" />

    <!-- 录制 -->
    <el-button
      size="small"
      :type="state?.recording.isRecording ? 'danger' : 'default'"
      :loading="busy.recording"
      @click="toggleRecording"
    >
      <el-icon v-if="state?.recording.isRecording"><VideoPause /></el-icon>
      <el-icon v-else><VideoCamera /></el-icon>
      <span class="btn-label">{{ recordLabel }}</span>
    </el-button>

    <!-- 回放 -->
    <el-button
      size="small"
      :type="state?.recording.isPlaying ? 'warning' : 'default'"
      :loading="busy.playback"
      @click="togglePlayback"
    >
      <el-icon v-if="state?.recording.isPlaying"><CircleClose /></el-icon>
      <el-icon v-else><VideoPlay /></el-icon>
      <span class="btn-label">{{ state?.recording.isPlaying ? '退出回放' : '回放' }}</span>
    </el-button>

    <!-- 录像管理 -->
    <el-button size="small" @click="openManageDialog">
      <el-icon><Document /></el-icon>
      <span class="btn-label">录像管理</span>
    </el-button>

    <!-- 2D / 3D 视图切换 -->
    <el-button
      size="small"
      :type="view2D ? 'primary' : 'default'"
      :loading="busy.view"
      @click="toggleViewMode"
    >
      <el-icon><View /></el-icon>
      <span class="btn-label">{{ view2D ? '2D' : '3D' }}</span>
    </el-button>

    <!-- 车辆自动跟随（需先选中车辆） -->
    <el-button
      size="small"
      :type="cameraFollowing ? 'warning' : 'default'"
      :disabled="!cameraFollowing && followCarId == null"
      :loading="busy.follow"
      @click="toggleCameraFollow"
    >
      <el-icon><Aim /></el-icon>
      <span class="btn-label">{{ cameraFollowing ? '停止跟随' : '自动跟随' }}</span>
    </el-button>

    <!-- 选择录像（回放）对话框 -->
    <el-dialog
      v-model="playDialogVisible"
      title="选择录像回放"
      width="640px"
      append-to-body
      destroy-on-close
    >
      <el-empty v-if="!state || state.recording.entries.length === 0" description="（无可用录像。点 ● 录制 创建首份录像。）" />
      <el-table v-else :data="state.recording.entries" size="small" stripe>
        <el-table-column prop="fileName" label="文件名" min-width="180" />
        <el-table-column label="大小" width="90">
          <template #default="{ row }">{{ formatSize(row.fileSizeBytes) }}</template>
        </el-table-column>
        <el-table-column prop="frameCount" label="帧" width="70" />
        <el-table-column label="时长" width="100">
          <template #default="{ row }">{{ formatDuration(row.durationMs) }}</template>
        </el-table-column>
        <el-table-column label="时间" width="160">
          <template #default="{ row }">{{ formatDate(row.fileWriteTime) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="100" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" :disabled="!row.headerReadable" @click="playRecording(row.fileName)">回放</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>

    <!-- 录像管理对话框 -->
    <el-dialog
      v-model="manageDialogVisible"
      title="录像管理"
      width="780px"
      append-to-body
      destroy-on-close
    >
      <p class="muted-hint">目录：{{ state?.recording.recordingsDirectory ?? '—' }}</p>
      <el-empty v-if="!state || state.recording.entries.length === 0" description="（无可用录像。）" />
      <el-table v-else :data="state.recording.entries" size="small" stripe>
        <el-table-column prop="fileName" label="文件名" min-width="200" />
        <el-table-column label="大小" width="90">
          <template #default="{ row }">{{ formatSize(row.fileSizeBytes) }}</template>
        </el-table-column>
        <el-table-column prop="frameCount" label="帧" width="70" />
        <el-table-column label="时长" width="100">
          <template #default="{ row }">{{ formatDuration(row.durationMs) }}</template>
        </el-table-column>
        <el-table-column label="时间" width="160">
          <template #default="{ row }">{{ formatDate(row.fileWriteTime) }}</template>
        </el-table-column>
        <el-table-column label="状态" width="120">
          <template #default="{ row }">
            <el-tag v-if="row.headerReadable" type="success" size="small">完整</el-tag>
            <el-tooltip v-else :content="row.error" placement="top">
              <el-tag type="danger" size="small">头部不可读</el-tag>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="160" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" :disabled="!row.headerReadable" @click="playRecording(row.fileName)">回放</el-button>
            <el-button link type="danger" @click="deleteRecording(row.fileName)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  Operation,
  Pointer,
  Files,
  View,
  VideoCamera,
  VideoPause,
  VideoPlay,
  CircleClose,
  Document,
  ArrowUp,
  FirstAidKit,
  Aim
} from '@element-plus/icons-vue'
import {
  workspaceToolbarApi,
  type AlignKey,
  type DisplayKey,
  type SelectKey,
  type ToolbarState
} from '@/api/workspaceToolbar'

const props = withDefaults(
  defineProps<{
    /** 当前选中的车辆 numeric id（地图监控侧栏/画布选中车辆时传入） */
    followCarId?: number | null
  }>(),
  { followCarId: null }
)

const emit = defineEmits<{
  (e: 'state-changed', state: ToolbarState): void
  (e: 'follow-changed', payload: { enabled: boolean; carId: number | null }): void
}>()

function publishState(next: ToolbarState | null) {
  if (!next) return
  emit('state-changed', next)
}

/**
 * 平台 iframe 画布工具栏（对应 SimpleLite `Panel_4` / `WorkspaceBottomBar.DefineForTerminalEmbedMinimal`）。
 *
 * 设计原则：
 *   - 所有状态都通过 `/sl/projection/toolbar/*` 走 SimpleLite 全局状态，多 tab 同源。
 *   - `state` 是后端权威单一真值；本地不维护"乐观"切换：每次 toggle 都拿后端最新返回回写。
 *   - 录制 / 回放期间 1Hz 轮询刷新 elapsed / 帧计数，避免页面打开后停留在初值。
 *   - 错误用 ElMessage.error 提示，不阻断画布主操作。
 */

const ALIGN_OPTIONS: { key: AlignKey; label: string }[] = [
  { key: 'sites', label: '站点' },
  { key: 'cars', label: 'AGV' },
  { key: 'tracks', label: '路径' }
]

const SELECT_OPTIONS: { key: SelectKey; label: string }[] = [
  { key: 'tracks', label: '路径' },
  { key: 'cars', label: 'AGV' },
  { key: 'decor', label: '区域/装饰' },
  { key: 'sites', label: '站点' }
]

const DISPLAY_OPTIONS: { key: DisplayKey; label: string }[] = [
  { key: 'labels', label: '场景图元标记' },
  { key: 'primitives', label: '场景图元' },
  { key: 'cars', label: '车辆' }
]

const state = ref<ToolbarState | null>(null)
const busy = reactive({
  align: false,
  select: false,
  display: false,
  layer: false,
  recording: false,
  playback: false,
  view: false,
  follow: false
})

const playDialogVisible = ref(false)
const manageDialogVisible = ref(false)

let pollTimer: ReturnType<typeof setInterval> | null = null

const recordLabel = computed(() => {
  const r = state.value?.recording
  if (!r?.isRecording) return '录制'
  const sec = Math.floor((r.elapsedMs ?? 0) / 1000)
  const mm = String(Math.floor(sec / 60)).padStart(2, '0')
  const ss = String(sec % 60).padStart(2, '0')
  return `停止 ${mm}:${ss}`
})

const view2D = computed(() => state.value?.view?.map2D ?? true)

const cameraFollowing = computed(() => state.value?.view?.follow?.enabled ?? false)

const followCarId = computed(() => {
  const fromProp = props.followCarId
  if (fromProp != null && Number.isFinite(fromProp)) return fromProp
  const fromState = state.value?.view?.follow?.carId
  return fromState != null && Number.isFinite(fromState) ? fromState : null
})

async function refresh() {
  try {
    state.value = await workspaceToolbarApi.getState()
    publishState(state.value)
  } catch (err) {
    ElMessage.error(`同步工具栏状态失败：${(err as Error).message}`)
  }
}

async function toggleAlign(key: AlignKey) {
  if (!state.value) return
  busy.align = true
  try {
    state.value = await workspaceToolbarApi.setAlign(key, !state.value.align[key])
    publishState(state.value)
  } catch (err) {
    ElMessage.error(`切换对齐失败：${(err as Error).message}`)
  } finally {
    busy.align = false
  }
}

async function toggleSelect(key: SelectKey) {
  if (!state.value) return
  busy.select = true
  try {
    state.value = await workspaceToolbarApi.setSelect(key, !state.value.select[key])
    publishState(state.value)
  } catch (err) {
    ElMessage.error(`切换选择过滤失败：${(err as Error).message}`)
  } finally {
    busy.select = false
  }
}

async function toggleDisplay(key: DisplayKey) {
  if (!state.value) return
  busy.display = true
  try {
    state.value = await workspaceToolbarApi.setDisplay(key, !state.value.display[key])
    publishState(state.value)
  } catch (err) {
    ElMessage.error(`切换显示内容失败：${(err as Error).message}`)
  } finally {
    busy.display = false
  }
}

async function toggleLayer(name: string, visible: boolean) {
  busy.layer = true
  try {
    state.value = await workspaceToolbarApi.setLayerVisibility(name, visible)
    publishState(state.value)
  } catch (err) {
    ElMessage.error(`切换图层失败：${(err as Error).message}`)
  } finally {
    busy.layer = false
  }
}

function onContextMenuPlaceholder() {
  ElMessage.info('寻路右键动作尚未接入 SimpleLite；请使用 SegmentPlan.FindRoute / 工作台脚本。')
}

async function toggleRecording() {
  const cur = state.value?.recording
  if (!cur) return
  if (cur.isPlaying) {
    ElMessage.warning('当前在回放中，请先停止回放。')
    return
  }
  busy.recording = true
  try {
    state.value = cur.isRecording
      ? await workspaceToolbarApi.stopRecording()
      : await workspaceToolbarApi.startRecording('')
  } catch (err) {
    ElMessage.error(`录制操作失败：${(err as Error).message}`)
  } finally {
    busy.recording = false
  }
}

async function togglePlayback() {
  const cur = state.value?.recording
  if (!cur) return
  if (cur.isRecording) {
    ElMessage.warning('录制中无法进入回放，请先停止录制。')
    return
  }
  if (cur.isPlaying) {
    busy.playback = true
    try {
      state.value = await workspaceToolbarApi.stopPlayback()
    } catch (err) {
      ElMessage.error(`停止回放失败：${(err as Error).message}`)
    } finally {
      busy.playback = false
    }
    return
  }
  await refresh()
  playDialogVisible.value = true
}

async function playRecording(fileName: string) {
  busy.playback = true
  try {
    state.value = await workspaceToolbarApi.startPlayback(fileName)
    playDialogVisible.value = false
    manageDialogVisible.value = false
    ElMessage.success(`已开始回放 ${fileName}`)
  } catch (err) {
    ElMessage.error(`启动回放失败：${(err as Error).message}`)
  } finally {
    busy.playback = false
  }
}

async function deleteRecording(fileName: string) {
  try {
    await ElMessageBox.confirm(`确认删除录像 ${fileName}？此操作不可恢复。`, '删除录像', { type: 'warning' })
  } catch { return }
  try {
    state.value = await workspaceToolbarApi.deleteRecording(fileName)
    ElMessage.success(`已删除 ${fileName}`)
  } catch (err) {
    ElMessage.error(`删除失败：${(err as Error).message}`)
  }
}

async function openManageDialog() {
  await refresh()
  manageDialogVisible.value = true
}

async function toggleViewMode() {
  busy.view = true
  try {
    state.value = await workspaceToolbarApi.toggleViewMode()
  } catch (err) {
    ElMessage.error(`切换视图失败：${(err as Error).message}`)
  } finally {
    busy.view = false
  }
}

async function toggleCameraFollow() {
  const carId = followCarId.value
  if (!cameraFollowing.value && (carId == null || !Number.isFinite(carId))) {
    ElMessage.warning('请先在车辆列表或 3D 画布中选中一辆车')
    return
  }
  busy.follow = true
  try {
    const enable = !cameraFollowing.value
    state.value = await workspaceToolbarApi.setCameraFollow(carId, enable)
    publishState(state.value)
    emit('follow-changed', { enabled: enable, carId: enable ? carId : null })
    if (enable) {
      ElMessage.success({ message: `已开始跟随车辆 #${carId}`, duration: 1500, grouping: true })
    } else {
      ElMessage.info('已停止自动跟随')
    }
  } catch (err) {
    ElMessage.error(`自动跟随失败：${(err as Error).message}`)
  } finally {
    busy.follow = false
  }
}

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

function formatDuration(ms: number): string {
  if (!Number.isFinite(ms) || ms <= 0) return '00:00:00'
  const sec = Math.floor(ms / 1000)
  const h = String(Math.floor(sec / 3600)).padStart(2, '0')
  const m = String(Math.floor((sec % 3600) / 60)).padStart(2, '0')
  const s = String(sec % 60).padStart(2, '0')
  return `${h}:${m}:${s}`
}

function formatDate(iso: string): string {
  if (!iso) return '—'
  const d = new Date(iso)
  if (isNaN(d.getTime())) return iso
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

onMounted(() => {
  void refresh()
  pollTimer = setInterval(() => {
    const r = state.value?.recording
    if (r?.isRecording || r?.isPlaying || state.value?.view?.follow?.enabled) void refresh()
  }, 1000)
})

onBeforeUnmount(() => {
  if (pollTimer) clearInterval(pollTimer)
  if (cameraFollowing.value) {
    void workspaceToolbarApi.setCameraFollow(null, false).catch(() => {})
  }
})
</script>

<style scoped>
.canvas-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: rgba(0, 0, 0, 0.45);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  border-bottom-left-radius: var(--mg-radius, 16px);
  border-bottom-right-radius: var(--mg-radius, 16px);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  flex-wrap: wrap;
}
.canvas-toolbar :deep(.el-button) {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.btn-label {
  margin-left: 2px;
}
.caret {
  margin-left: 2px;
  font-size: 10px;
  opacity: 0.7;
}
.separator {
  width: 1px;
  height: 18px;
  background: rgba(255, 255, 255, 0.18);
  margin: 0 4px;
}
.toolbar-menu .menu-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 14px;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  color: var(--el-text-color-primary);
}
.toolbar-menu .menu-row:hover {
  background: var(--el-fill-color-light);
}
.toolbar-menu .menu-row :deep(.el-checkbox) {
  margin-right: 0;
  pointer-events: none;
}
.layer-menu {
  max-height: 320px;
  overflow-y: auto;
}
.menu-empty {
  padding: 10px 14px;
  color: var(--el-text-color-secondary);
  font-size: 12px;
}
.muted-hint {
  margin: 0 0 8px;
  color: var(--el-text-color-secondary);
  font-size: 12px;
}
</style>
