<template>
  <div class="page-container">
    <!-- 搜索表单 -->
    <div class="search-form">
      <el-form :model="searchForm" inline>
        <el-form-item>
          <el-input
            v-model.trim="searchForm.streamSn"
            :placeholder="t('stream sn')"
            clearable
            @keyup.enter="handleSearch"
          />
        </el-form-item>
        <el-form-item>
          <el-input v-model.trim="searchForm.name" :placeholder="t('名称')" clearable @keyup.enter="handleSearch" />
        </el-form-item>
        <el-form-item>
          <el-select v-model="searchForm.lssId" placeholder="LSS" clearable filterable style="width: 180px">
            <el-option v-for="lss in lssOptions" :key="lss.lssId" :label="lss.lssId" :value="lss.lssId" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-input
            v-model.trim="searchForm.cameraId"
            :placeholder="t('设备ID')"
            clearable
            @keyup.enter="handleSearch"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" :icon="Search" @click="handleSearch">{{ t('查询') }}</el-button>
          <el-button type="info" :icon="RefreshRight" @click="handleReset">{{ t('重置') }}</el-button>
          <el-button type="primary" :icon="Plus" @click="handleAdd">{{ t('新增') }}</el-button>
        </el-form-item>
      </el-form>
    </div>

    <!-- 数据表格 -->
    <div class="table-wrapper">
      <el-table
        ref="tableRef"
        v-loading="loading"
        :data="streamList"
        stripe
        size="default"
        height="100%"
        @sort-change="handleSortChange"
      >
        <el-table-column prop="streamSn" :label="t('stream sn')" width="220" show-overflow-tooltip>
          <template #default="{ row }">
            <el-link type="primary" @click="handleEdit(row)">{{ row.streamSn }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="name" :label="t('名称')" show-overflow-tooltip>
          <template #default="{ row }">
            <span>{{ row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="lssId" :label="t('LSS')" width="160" show-overflow-tooltip>
          <template #default="{ row }">
            <span>{{ row.lssId || '-' }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="cameraId" :label="t('设备ID')" show-overflow-tooltip>
          <template #default="{ row }">
            <span>{{ row.cameraId || '-' }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="pushMethod" :label="t('推流方式')" align="center">
          <template #default="{ row }">
            <el-tag size="small">{{ row.pushMethod || 'ffmpeg' }}</el-tag>
          </template>
        </el-table-column>

        <el-table-column prop="commandTemplate" :label="t('命令模板')" align="center">
          <template #default="{ row }">
            <el-link type="primary" @click="openCommandDialog(row)">{{ t('查看') }}</el-link>
          </template>
        </el-table-column>
        <el-table-column :label="t('推流控制')" width="110" align="center">
          <template #default="{ row }">
            {{ row.status === '1' ? t('开启') : t('关闭') }}
            <el-switch
              :model-value="row.status === '1'"
              :loading="row._starting || row._stopping"
              inline-prompt
              @change="(val: boolean) => handleToggleStream(row, val)"
            />
          </template>
        </el-table-column>
        <el-table-column prop="startedAt" :label="t('启动时间')" width="165" align="center">
          <template #default="{ row }">
            {{ formatTime(row.startedAt) }}
          </template>
        </el-table-column>
        <el-table-column prop="stoppedAt" :label="t('关闭时间')" width="165" align="center">
          <template #default="{ row }">
            {{ formatTime(row.stoppedAt) }}
          </template>
        </el-table-column>
        <el-table-column :label="t('操作')" fixed="right" min-width="130">
          <template #default="{ row }">
            <el-button type="primary" link @click="handleEdit(row)">
              <Icon icon="mdi:note-edit-outline" width="20" height="20" />
            </el-button>
            <el-button data-id="live-stream-play-btn" type="primary" link @click="handleViewCloudflare(row)">
              <Icon icon="mdi:play-circle-outline" width="20" height="20" />
            </el-button>
            <el-button type="danger" link @click="handleDelete(row)">
              <Icon icon="mdi:delete" width="20" height="20" />
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <!-- 分页 -->
    <div class="pagination-container">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="[10, 20, 50, 100]"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        background
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>

    <!-- 合并的编辑/播放抽屉 -->
    <el-drawer
      v-model="drawerVisible"
      direction="rtl"
      :size="activeDrawerTab === 'edit' ? '800px' : '90%'"
      :with-header="false"
      destroy-on-close
      class="combined-drawer"
    >
      <div class="drawer-content">
        <!-- 顶部 Tabs -->
        <el-tabs v-model="activeDrawerTab" class="drawer-tabs">
          <el-tab-pane :label="t('编辑')" name="edit" />
          <el-tab-pane :label="t('播放')" name="play" :disabled="!isEdit" />
        </el-tabs>

        <!-- 编辑 Tab 内容 -->
        <div v-show="activeDrawerTab === 'edit'" class="tab-content edit-content">
          <div class="drawer-body">
            <el-form ref="formRef" :model="form" :rules="rules" label-width="auto" class="stream-form">
              <el-form-item :label="t('名称') + ':'" prop="name">
                <el-input v-model="form.name" :placeholder="t('例如: 测试推流-001')" style="width: 300px" />
              </el-form-item>
              <el-form-item :label="t('LSS 节点') + ':'" prop="lssId">
                <el-select
                  v-model="form.lssId"
                  :placeholder="t('请选择 LSS 节点')"
                  clearable
                  filterable
                  style="width: 300px"
                >
                  <el-option
                    v-for="lss in lssOptions"
                    :key="lss.lssId"
                    :label="`${lss.lssId} - ${lss.lssName}`"
                    :value="lss.lssId"
                  />
                </el-select>
              </el-form-item>
              <el-form-item :label="t('摄像头') + ':'" prop="cameraId">
                <el-select
                  v-model="form.cameraId"
                  :placeholder="t('请选择摄像头')"
                  clearable
                  filterable
                  style="width: 300px"
                >
                  <el-option
                    v-for="camera in cameraOptions"
                    :key="camera.cameraId"
                    :label="`${camera.cameraId} - ${camera.cameraName}`"
                    :value="camera.cameraId"
                  />
                </el-select>
              </el-form-item>
              <el-form-item :label="t('推流方式') + ':'" prop="pushMethod">
                <el-select disabled v-model="form.pushMethod" :placeholder="t('请选择')" style="width: 300px">
                  <el-option label="ffmpeg" value="ffmpeg" />
                </el-select>
              </el-form-item>
              <el-form-item :label="t('命令模板') + ':'" prop="commandTemplate">
                <CodeEditor
                  v-model="form.commandTemplate"
                  language="bash"
                  height="400px"
                  placeholder="#!/bin/bash&#10;# FFmpeg 命令模板，可使用 {RTSP_URL} 等变量"
                />
              </el-form-item>
            </el-form>
          </div>
          <div class="drawer-footer">
            <el-button @click="drawerVisible = false">{{ t('取消') }}</el-button>
            <el-button type="primary" :loading="submitLoading" @click="handleSubmit">
              {{ isEdit ? t('更新') : t('添加') }}
            </el-button>
          </div>
        </div>

        <!-- 播放 Tab 内容 -->
        <div v-show="activeDrawerTab === 'play'" class="tab-content play-content">
          <div class="media-drawer-content">
            <!-- 左侧：视频播放区域 -->
            <div class="video-area">
              <div class="video-header">
                <div class="header-left">
                  <span class="title">{{ currentMediaStream?.name || t('流媒体播放') }}</span>
                  <el-tag v-if="playbackInfo.isLive" type="success" size="small">{{ t('直播中') }}</el-tag>
                  <el-tag v-else type="info" size="small">{{ t('离线') }}</el-tag>
                </div>
                <!-- <el-button type="danger" size="small" @click="drawerVisible = false">
                  <Icon icon="mdi:close" width="16" height="16" />
                  {{ t('关闭') }}
                </el-button> -->
                <el-button
                  v-if="currentMediaStream && currentMediaStream.status === '1'"
                  type="danger"
                  size="small"
                  :loading="streamStopping"
                  @click="handleStopStreamFromPlayer"
                >
                  {{ t('停止推流') }}
                </el-button>
              </div>
              <div class="player-container">
                <div v-if="!playbackInfo.videoId" class="player-placeholder">
                  <el-icon :size="80" color="#666">
                    <VideoPlay />
                  </el-icon>
                  <p>{{ t('暂无视频流') }}</p>
                </div>
                <VideoPlayer
                  v-else
                  ref="playerRef"
                  player-type="cloudflare"
                  :video-id="playbackInfo.videoId"
                  :customer-domain="playbackInfo.customerDomain"
                  :use-iframe="true"
                  :autoplay="playConfig.autoplay"
                  :muted="playConfig.muted"
                  :controls="true"
                />
                <!-- 开始推流按钮 -->
                <div v-if="currentMediaStream && currentMediaStream.status !== '1'" class="stream-control-overlay">
                  <el-button type="success" size="large" :loading="streamStarting" @click="handleStartStreamFromPlayer">
                    {{ t('开始推流') }}
                  </el-button>
                </div>
              </div>

              <!-- 时间轴操作条 -->
              <div class="timeline-container">
                <!-- 时间轴头部 -->
                <div class="timeline-header">
                  <span class="timeline-label">{{ t('巡航时间轴') }}</span>
                  <el-select
                    v-model="timelineDuration"
                    size="small"
                    style="width: 100px"
                    :disabled="isTimelinePlaying"
                    @change="handleDurationChange"
                  >
                    <el-option :value="60" :label="t('1分钟')" />
                    <el-option :value="180" :label="t('3分钟')" />
                    <el-option :value="300" :label="t('5分钟')" />
                    <el-option :value="600" :label="t('10分钟')" />
                  </el-select>
                  <el-button size="small" :disabled="isTimelinePlaying" @click="addTimelinePoint()">
                    + {{ t('添加点') }}
                  </el-button>
                  <el-switch
                    v-model="isLoopEnabled"
                    :disabled="isTimelinePlaying"
                    size="small"
                    :active-text="t('循环')"
                    style="margin-left: 8px"
                  />
                  <el-button
                    size="small"
                    type="primary"
                    :loading="isTimelinePlaying"
                    :disabled="!hasActivePoints"
                    @click="playTimeline"
                  >
                    <el-icon v-if="!isTimelinePlaying">
                      <VideoPlay />
                    </el-icon>
                    {{ isTimelinePlaying ? t('巡航中...') : t('播放巡航') }}
                  </el-button>
                  <el-button v-if="isTimelinePlaying" size="small" type="danger" @click="stopTimeline">
                    {{ t('停止') }}
                  </el-button>
                </div>

                <!-- 时间轴轨道 -->
                <div :class="['timeline-track', { 'is-playing': isTimelinePlaying }]" ref="timelineTrackRef">
                  <!-- 时间轴进度指示器 -->
                  <div class="timeline-progress" :style="{ width: `${timelineProgress}%` }"></div>
                  <!-- 关键点 -->
                  <div
                    v-for="point in timelinePoints"
                    :key="point.id"
                    :class="[
                      'timeline-point',
                      {
                        active: point.active,
                        selected: !isTimelinePlaying && selectedPoint?.id === point.id,
                        dragging: draggingPoint?.id === point.id
                      }
                    ]"
                    :style="{ left: `${(point.time / timelineDuration) * 100}%` }"
                    @click.stop="!isTimelinePlaying && selectPoint(point)"
                    @mousedown.stop="!isTimelinePlaying && startDragPoint($event, point)"
                    @contextmenu.prevent="!isTimelinePlaying && handlePointContextMenu($event, point)"
                  >
                    <span class="point-label">{{ point.id }}</span>
                    <div class="point-tooltip">
                      <div>{{ point.presetName || `Point ${point.id}` }}</div>
                      <div class="point-time">{{ formatTimelineTime(point.time) }}</div>
                    </div>
                  </div>
                </div>

                <!-- 时间刻度 -->
                <div class="timeline-scale">
                  <span v-for="i in Math.floor(timelineDuration / 60) + 1" :key="i" class="scale-mark">
                    {{ formatTimelineTime((i - 1) * 60) }}
                  </span>
                </div>

                <!-- 选中点的操作面板（巡航中隐藏） -->
                <div v-if="selectedPoint && !isTimelinePlaying" class="timeline-point-panel">
                  <span class="panel-label">
                    {{ t('当前选中') }}: {{ selectedPoint.presetName || `Point ${selectedPoint.id}` }}
                  </span>
                  <!-- 关联已有预置位 -->
                  <el-select
                    v-model="linkPresetId"
                    size="small"
                    :placeholder="t('关联预置位')"
                    style="width: 140px"
                    clearable
                    @change="handleLinkPreset"
                  >
                    <el-option
                      v-for="preset in ptzPresetList"
                      :key="preset.id"
                      :value="preset.id"
                      :label="preset.name || `Preset ${preset.id}`"
                    />
                  </el-select>
                  <el-button size="small" type="primary" :loading="savingPreset" @click="saveCurrentPoint">
                    {{ selectedPoint.active ? t('更新位置') : t('保存位置') }}
                  </el-button>
                  <el-button size="small" type="danger" @click="deleteSelectedPoint">{{ t('删除') }}</el-button>
                </div>
                <!-- 自动映射按钮（巡航中隐藏） -->
                <div v-if="timelinePoints.length > 0 && !isTimelinePlaying" class="timeline-auto-link">
                  <el-button
                    size="small"
                    type="success"
                    @click="autoLinkPresets"
                    :disabled="ptzPresetList.length === 0"
                  >
                    <el-icon>
                      <Link />
                    </el-icon>
                    {{ t('自动映射') }}
                  </el-button>
                  <span class="auto-link-hint">{{ t('将点1-N映射到Preset 1-N') }}</span>
                </div>
              </div>

              <!-- 底部播放控制 -->
              <!-- <div class="player-controls">
                <el-button type="primary" size="small" @click="handlePlay">{{ t('播放') }}</el-button>
                <el-button size="small" @click="handlePause">{{ t('暂停') }}</el-button>
                <el-button type="danger" size="small" @click="handlePlayerStop">{{ t('停止') }}</el-button>
                <el-button size="small" @click="handleScreenshot">{{ t('截图') }}</el-button>
                <el-button size="small" @click="handleFullscreen">{{ t('全屏') }}</el-button>
                <el-switch
                  v-model="playConfig.muted"
                  :active-text="t('静音')"
                  :inactive-text="t('有声')"
                  style="margin-left: 16px"
                />
                <el-divider direction="vertical" />
              </div> -->
            </div>

            <!-- 右侧：PTZ 控制面板 -->
            <div class="control-panel">
              <el-collapse v-model="activePanels" class="ptz-collapse">
                <!-- PTZ 方向控制 -->
                <el-collapse-item name="ptz">
                  <template #title>
                    <span class="collapse-title">{{ t('PTZ') }}</span>
                  </template>
                  <div class="ptz-grid">
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('UP_LEFT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <TopLeft />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('UP')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <Top />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('UP_RIGHT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <TopRight />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('LEFT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <Back />
                      </el-icon>
                    </div>
                    <div class="ptz-btn ptz-center" @click="handlePTZStop">
                      <el-icon>
                        <Refresh />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('RIGHT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <Right />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('DOWN_LEFT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <BottomLeft />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('DOWN')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <Bottom />
                      </el-icon>
                    </div>
                    <div
                      class="ptz-btn"
                      @mousedown="handlePTZ('DOWN_RIGHT')"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <BottomRight />
                      </el-icon>
                    </div>
                  </div>

                  <!-- 缩放按钮 -->
                  <div class="zoom-buttons">
                    <el-button
                      size="small"
                      @mousedown="handleZoomIn"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <ZoomIn />
                      </el-icon>
                    </el-button>
                    <el-button
                      size="small"
                      @mousedown="handleZoomOut"
                      @mouseup="handlePTZStop"
                      @mouseleave="handlePTZStop"
                    >
                      <el-icon>
                        <ZoomOut />
                      </el-icon>
                    </el-button>
                  </div>

                  <!-- 速度滑块 -->
                  <div class="speed-slider">
                    <span class="label">{{ t('速度') }}</span>
                    <el-slider v-model="ptzSpeed" :min="10" :max="100" :step="10" size="small" />
                    <span class="value">{{ ptzSpeed }}</span>
                  </div>
                </el-collapse-item>

                <!-- 预置位列表 -->
                <el-collapse-item name="preset">
                  <template #title>
                    <div class="collapse-title-with-action">
                      <span class="collapse-title">{{ t('预置位') }}</span>
                      <el-button
                        type="primary"
                        link
                        size="small"
                        @click.stop="loadPTZPresets"
                        :loading="presetsLoading"
                      >
                        <el-icon>
                          <Refresh />
                        </el-icon>
                      </el-button>
                    </div>
                  </template>
                  <div class="preset-list" v-loading="presetsLoading">
                    <div
                      v-for="preset in ptzPresetList"
                      :key="preset.id"
                      :class="['preset-item', { active: activePresetId === preset.id.toString() }]"
                    >
                      <span class="preset-index">{{ preset.id }}</span>
                      <span class="preset-name">{{ preset.name || `Preset ${preset.id}` }}</span>
                      <div class="preset-actions">
                        <el-tooltip :content="t('跳转')" placement="top">
                          <el-icon class="action-icon" @click="handleGotoPTZPreset(preset)">
                            <Position />
                          </el-icon>
                        </el-tooltip>
                        <el-tooltip :content="t('设置')" placement="top">
                          <el-icon class="action-icon" @click="handleEditPreset(preset)">
                            <Setting />
                          </el-icon>
                        </el-tooltip>
                        <el-tooltip :content="t('删除')" placement="top">
                          <el-icon class="action-icon delete" @click="handleDeletePreset(preset)">
                            <Close />
                          </el-icon>
                        </el-tooltip>
                      </div>
                    </div>
                    <el-empty
                      v-if="!presetsLoading && ptzPresetList.length === 0"
                      :description="t('暂无预置位')"
                      :image-size="60"
                    />
                  </div>
                </el-collapse-item>

                <!-- 摄像头信息 -->
                <el-collapse-item name="camera">
                  <template #title>
                    <span class="collapse-title">{{ t('摄像头信息') }}</span>
                  </template>
                  <div class="camera-info-content" v-loading="capabilitiesLoading">
                    <template v-if="cameraCapabilities">
                      <div class="info-item">
                        <span class="info-label">{{ t('最大预置位') }}:</span>
                        <span class="info-value">{{ cameraCapabilities.maxPresetNum || '-' }}</span>
                      </div>
                      <div class="info-item" v-if="cameraCapabilities.controlProtocol">
                        <span class="info-label">{{ t('控制协议') }}:</span>
                        <span class="info-value">{{ cameraCapabilities.controlProtocol.current }}</span>
                      </div>
                      <div class="info-item" v-if="cameraCapabilities.absoluteZoom">
                        <span class="info-label">{{ t('变焦倍数') }}:</span>
                        <span class="info-value">
                          {{ cameraCapabilities.absoluteZoom.min }}x - {{ cameraCapabilities.absoluteZoom.max }}x
                        </span>
                      </div>
                      <div class="info-item" v-if="cameraCapabilities.support3DPosition !== undefined">
                        <span class="info-label">{{ t('3D定位') }}:</span>
                        <span class="info-value">
                          {{ cameraCapabilities.support3DPosition ? t('支持') : t('不支持') }}
                        </span>
                      </div>
                      <div class="info-item" v-if="cameraCapabilities.supportPtzLimits !== undefined">
                        <span class="info-label">{{ t('PTZ限位') }}:</span>
                        <span class="info-value">
                          {{ cameraCapabilities.supportPtzLimits ? t('支持') : t('不支持') }}
                        </span>
                      </div>
                    </template>
                    <el-empty
                      v-else-if="!capabilitiesLoading"
                      :description="currentMediaStream?.cameraId ? t('点击刷新加载') : t('请选择直播流')"
                      :image-size="40"
                    />
                  </div>
                </el-collapse-item>
              </el-collapse>
            </div>
          </div>
        </div>
      </div>
    </el-drawer>

    <!-- 命令模板查看/编辑抽屉 -->
    <el-drawer v-model="commandDialogVisible" :title="t('命令模板')" direction="rtl" size="800px" destroy-on-close>
      <div class="command-template-container">
        <CodeEditor
          v-model="currentCommandTemplate"
          language="bash"
          height="450px"
          placeholder="#!/bin/bash&#10;# FFmpeg 推流命令模板"
        />
      </div>
      <template #footer>
        <div class="drawer-footer">
          <el-button @click="commandDialogVisible = false">{{ t('取消') }}</el-button>
          <el-button type="primary" :loading="commandUpdateLoading" @click="handleUpdateCommandTemplate">
            {{ t('更新') }}
          </el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
import {
  Search,
  RefreshRight,
  Plus,
  VideoPlay,
  Top,
  Bottom,
  Back,
  Right,
  TopLeft,
  TopRight,
  BottomLeft,
  BottomRight,
  Refresh,
  ZoomIn,
  ZoomOut,
  Close,
  Position,
  Link
} from '@element-plus/icons-vue'
import { Icon } from '@iconify/vue'
import { useI18n } from 'vue-i18n'
import { formatTime } from '@/utils/dayjs'
import { listLiveStreams, addLiveStream, updateLiveStream, deleteLiveStream } from '@/api/live-stream'
import { listAllLssNodes } from '@/api/lss'
import { adminListCameras } from '@/api/camera'
import { startStreamTask, stopStreamTask, getStreamPlayback } from '@/api/stream-push'
import VideoPlayer from '@/components/VideoPlayer.vue'
import CodeEditor from '@/components/CodeEditor.vue'
import {
  type PresetInfo,
  presetList,
  presetGoto,
  presetSet,
  presetRemove,
  getPTZCapabilities,
  ptzControl
} from '@/api/camera'
import type { LiveStreamDTO, LiveStreamStatus, LssNodeDTO, CameraInfoDTO, StreamChannelDTO, PTZAction } from '@/types'

const { t } = useI18n({ useScope: 'global' })
const route = useRoute()
const router = useRouter()

const loading = ref(false)
const submitLoading = ref(false)
const streamList = ref<LiveStreamDTO[]>([])
const drawerVisible = ref(false)
const formRef = ref<FormInstance>()

// 命令模板弹窗
const commandDialogVisible = ref(false)
const currentCommandTemplate = ref('')
const currentStreamId = ref<number | null>(null)
const commandUpdateLoading = ref(false)

// 合并抽屉的 tab 状态
const activeDrawerTab = ref<'edit' | 'play'>('edit')
const currentMediaStream = ref<LiveStreamDTO | null>(null)
const streamStarting = ref(false)
const streamStopping = ref(false)
const playerRef = ref<InstanceType<typeof VideoPlayer>>()
const playbackInfo = ref<{
  videoId: string
  customerDomain: string
  hlsUrl?: string
  whepUrl?: string
  isLive: boolean
}>({
  videoId: '',
  customerDomain: '',
  isLive: false
})
const playConfig = reactive({
  autoplay: true,
  muted: true
})
// PTZ 控制
const ptzSpeed = ref(50)
const zoomValue = ref(0)

// 预置位
const presetsLoading = ref(false)

// PTZ 预置位 (camera API)
interface PTZPresetInfo {
  id: string
  name: string
}
interface PTZCapabilities {
  maxPresetNum?: number
  [key: string]: unknown
}
const ptzPresetList = ref<PresetInfo[]>([])
const activePresetId = ref<string | null>(null)
const cameraCapabilities = ref<PTZCapabilities | null>(null)
const capabilitiesLoading = ref(false)

// 可折叠面板
const activePanels = ref(['ptz', 'preset', 'camera'])

// ==================== 时间轴相关 ====================

// 时间轴关键点类型
interface TimelinePoint {
  id: number // 点的序号 (1, 2, 3...)
  time: number // 时间位置(秒)
  presetId?: number // 关联的预置位ID (保存后才有)
  presetName?: string // 预置位名称
  active: boolean // 是否已激活(已保存预置位)
}

// localStorage 存储 key
const TIMELINE_STORAGE_KEY = 'ptz_timeline_config'

// 时间轴状态
const timelineTrackRef = ref<HTMLElement | null>(null)
const timelineDuration = ref(180) // 总时长(秒)，默认3分钟
const timelinePoints = ref<TimelinePoint[]>([])
const selectedPoint = ref<TimelinePoint | null>(null)
const isTimelinePlaying = ref(false)
const timelineProgress = ref(0)
const savingPreset = ref(false)
const linkPresetId = ref<string | null>(null) // 关联预置位选择
const isLoopEnabled = ref(false) // 是否循环巡航
let timelinePlayAbort: AbortController | null = null

// 拖拽状态
const draggingPoint = ref<TimelinePoint | null>(null)

// 计算属性：是否有已激活的点
const hasActivePoints = computed(() => timelinePoints.value.some((p) => p.active))

// 下拉选项
const lssOptions = ref<LssNodeDTO[]>([])
const cameraOptions = ref<CameraInfoDTO[]>([])
const channelOptions = ref<StreamChannelDTO[]>([])

// 排序状态
const sortState = reactive<{
  prop: string
  order: 'ascending' | 'descending' | null
}>({
  prop: '',
  order: null
})

// 搜索表单
const searchForm = reactive<{
  streamSn: string
  name: string
  lssId: string
  cameraId: string
}>({
  streamSn: '',
  name: '',
  lssId: '',
  cameraId: ''
})

// 分页相关
const currentPage = ref(1)
const pageSize = ref(20)
const total = ref(0)

// 表单数据
const form = reactive<{
  id?: number
  name: string
  lssId: string
  cameraId: string
  channelId?: number
  pushMethod: string
  commandTemplate: string
  timeoutSeconds: number
  remark: string
  enabled: boolean
}>({
  name: '',
  lssId: '',
  cameraId: '',
  channelId: undefined,
  pushMethod: 'ffmpeg',
  commandTemplate: '',
  timeoutSeconds: 30,
  remark: '',
  enabled: true
})

const isEdit = computed(() => !!form.id)
const drawerTitle = computed(() => (isEdit.value ? t('编辑 Live Stream') : t('新增 Live Stream')))

const rules: FormRules = {
  name: [{ required: true, message: t('请输入名称'), trigger: 'blur' }],
  lssId: [{ required: true, message: t('请选择 LSS 节点'), trigger: 'change' }]
}

async function getList() {
  loading.value = true
  try {
    const params: Record<string, any> = {
      page: currentPage.value,
      size: pageSize.value
    }
    if (searchForm.streamSn) {
      params.streamSn = searchForm.streamSn
    }
    if (searchForm.name) {
      params.name = searchForm.name
    }
    if (searchForm.lssId) {
      params.lssId = searchForm.lssId
    }
    if (searchForm.cameraId) {
      params.cameraId = searchForm.cameraId
    }
    if (sortState.prop && sortState.order) {
      params.sortBy = sortState.prop
      params.sortDir = sortState.order === 'ascending' ? 'ASC' : 'DESC'
    }

    const res = await listLiveStreams(params)
    if (res.success) {
      streamList.value = res.data.list
      total.value = res.data.total || 0
    }
  } finally {
    loading.value = false
  }
}

async function loadOptions() {
  try {
    // 获取 LSS 节点列表
    const lssRes = await listAllLssNodes()
    if (lssRes.success && lssRes.data) {
      lssOptions.value = lssRes.data || []
    }
  } catch (error) {
    console.error('加载选项失败', error)
  }
}

// 监听 LSS 节点变化，加载对应的摄像头列表
watch(
  () => form.lssId,
  async (newLssId) => {
    // 清空当前选中的摄像头
    form.cameraId = ''
    cameraOptions.value = []

    if (newLssId) {
      try {
        const res = await adminListCameras({ lssId: newLssId, size: 1000 })
        if (res.success && res.data) {
          cameraOptions.value = res.data.list || []
        }
      } catch (error) {
        console.error('加载摄像头列表失败', error)
      }
    }
  }
)

function handleSearch() {
  currentPage.value = 1
  getList()
}

function handleReset() {
  searchForm.streamSn = ''
  searchForm.name = ''
  searchForm.lssId = ''
  searchForm.cameraId = ''
  currentPage.value = 1
  sortState.prop = ''
  sortState.order = null
  getList()
}

function handleSortChange({ prop, order }: { prop: string; order: 'ascending' | 'descending' | null }) {
  sortState.prop = prop || ''
  sortState.order = order
  getList()
}

function handleAdd() {
  Object.assign(form, {
    id: undefined,
    name: '',
    lssId: '',
    cameraId: '',
    channelId: undefined,
    pushMethod: 'ffmpeg',
    commandTemplate: '',
    timeoutSeconds: 30,
    remark: '',
    enabled: true
  })
  currentMediaStream.value = null
  activeDrawerTab.value = 'edit'
  drawerVisible.value = true
}

function handleEdit(row: LiveStreamDTO) {
  Object.assign(form, {
    id: row.id,
    name: row.name,
    lssId: row.lssId || '',
    cameraId: row.cameraId || '',
    channelId: row.channelId,
    pushMethod: row.pushMethod || 'ffmpeg',
    commandTemplate: row.commandTemplate || '',
    timeoutSeconds: row.timeoutSeconds || 30,
    remark: row.remark || '',
    enabled: row.enabled
  })
  currentMediaStream.value = row
  activeDrawerTab.value = 'edit'
  drawerVisible.value = true
}

async function handleDelete(row: LiveStreamDTO) {
  // 检查 status 必须为 0（已停止）
  if (row.status !== '0') {
    ElMessage.warning(t('只能删除已停止的 Live Stream'))
    return
  }

  // // 检查 stoppedAt 必须超过 24 小时
  // if (row.stoppedAt) {
  //   const stoppedTime = dayjs(row.stoppedAt)
  //   const hoursDiff = dayjs().diff(stoppedTime, 'hour')
  //   if (hoursDiff < 24) {
  //     ElMessage.warning(t('停止时间未超过24小时，暂时无法删除'))
  //     return
  //   }
  // } else {
  //   // 没有 stoppedAt 时间，不允许删除
  //   ElMessage.warning(t('停止时间未超过24小时，暂时无法删除'))
  //   return
  // }

  try {
    await ElMessageBox.confirm(t('确定要删除该 Live Stream 吗？'), t('提示'), {
      type: 'warning',
      confirmButtonText: t('确定'),
      cancelButtonText: t('取消')
    })

    const res = await deleteLiveStream(row.id)
    if (res.success) {
      ElMessage.success(t('删除成功'))
      getList()
    } else {
      ElMessage.error(res.errMessage || t('删除失败'))
    }
  } catch {
    // 用户取消
  }
}

async function handleSubmit() {
  if (!formRef.value) return

  await formRef.value.validate(async (valid) => {
    if (valid) {
      submitLoading.value = true
      try {
        if (isEdit.value) {
          const res = await updateLiveStream({
            id: form.id!,
            name: form.name,
            lssId: form.lssId || undefined,
            cameraId: form.cameraId || undefined,
            channelId: form.channelId,
            pushMethod: form.pushMethod || undefined,
            commandTemplate: form.commandTemplate || undefined,
            timeoutSeconds: form.timeoutSeconds,
            remark: form.remark || undefined,
            enabled: form.enabled
          })
          if (res.success) {
            ElMessage.success(t('修改成功'))
            drawerVisible.value = false
            getList()
          } else {
            ElMessage.error(res.errMessage || t('修改失败'))
          }
        } else {
          const res = await addLiveStream({
            name: form.name,
            lssId: form.lssId,
            cameraId: form.cameraId,
            channelId: form.channelId,
            pushMethod: form.pushMethod,
            commandTemplate: form.commandTemplate,
            timeoutSeconds: form.timeoutSeconds,
            remark: form.remark
          })
          if (res.success) {
            ElMessage.success(t('新增成功'))
            drawerVisible.value = false
            // 清除 URL 上的 lssId 和 action 参数
            if (route.query.action || route.query.lssId) {
              const newQuery = { ...route.query }
              delete newQuery.lssId
              delete newQuery.action
              router.replace({ path: '/live-stream', query: newQuery })
            }
            getList()
          } else {
            ElMessage.error(res.errMessage || t('新增失败'))
          }
        }
      } finally {
        submitLoading.value = false
      }
    }
  })
}

// 打开命令模板弹窗
function openCommandDialog(row: LiveStreamDTO) {
  currentStreamId.value = row.id
  currentCommandTemplate.value = row.commandTemplate || ''
  commandDialogVisible.value = true
}

// 更新命令模板
async function handleUpdateCommandTemplate() {
  if (!currentStreamId.value) return

  commandUpdateLoading.value = true
  try {
    const res = await updateLiveStream({
      id: currentStreamId.value,
      commandTemplate: currentCommandTemplate.value
    })
    if (res.success) {
      ElMessage.success(t('更新成功'))
      commandDialogVisible.value = false
      getList()
    } else {
      ElMessage.error(res.errMessage || t('更新失败'))
    }
  } catch (error) {
    console.error('更新命令模板失败', error)
    ElMessage.error(t('更新失败'))
  } finally {
    commandUpdateLoading.value = false
  }
}

// 切换推流状态
async function handleToggleStream(row: LiveStreamDTO, val: boolean) {
  if (val) {
    await handleStartStream(row)
  } else {
    await handleStopStream(row)
  }
}

// 启动推流
async function handleStartStream(row: LiveStreamDTO) {
  if (!row.cameraId) {
    ElMessage.warning(t('请先配置摄像头'))
    return
  }

  row._starting = true
  try {
    const res = await startStreamTask({
      name: row.name,
      lssId: row.lssId,
      cameraId: row.cameraId,
      commandTemplate: row.commandTemplate
    })
    if (res.success) {
      ElMessage.success(t('推流任务已启动'))
      getList()
    } else {
      ElMessage.error(res.errMessage || t('启动失败'))
    }
  } catch (error) {
    console.error('启动推流失败', error)
    ElMessage.error(t('启动推流失败'))
  } finally {
    row._starting = false
  }
}

// 从播放器窗口启动推流
async function handleStartStreamFromPlayer() {
  if (!currentMediaStream.value) return

  if (!currentMediaStream.value.cameraId) {
    ElMessage.warning(t('请先配置摄像头'))
    return
  }

  streamStarting.value = true
  try {
    const res = await startStreamTask({
      name: currentMediaStream.value.name,
      lssId: currentMediaStream.value.lssId,
      cameraId: currentMediaStream.value.cameraId,
      commandTemplate: currentMediaStream.value.commandTemplate
    })
    if (res.success) {
      ElMessage.success(t('推流任务已启动'))
      // 更新当前流的状态
      currentMediaStream.value.status = '1'
      // 刷新播放信息
      if (currentMediaStream.value.streamSn) {
        try {
          const playbackRes = await getStreamPlayback(currentMediaStream.value.streamSn)
          if (playbackRes.success && playbackRes.data) {
            playbackInfo.value = {
              ...playbackInfo.value,
              hlsUrl: playbackRes.data.hlsUrl,
              whepUrl: playbackRes.data.whepUrl,
              isLive: playbackRes.data.isLive
            }
          }
        } catch (e) {
          console.error('刷新播放信息失败', e)
        }
      }
      getList()
    } else {
      ElMessage.error(res.errMessage || t('启动失败'))
    }
  } catch (error) {
    console.error('启动推流失败', error)
    ElMessage.error(t('启动推流失败'))
  } finally {
    streamStarting.value = false
  }
}

// 从播放器窗口停止推流
async function handleStopStreamFromPlayer() {
  if (!currentMediaStream.value) return

  try {
    await ElMessageBox.confirm(t('确定要停止该推流任务吗？'), t('提示'), {
      type: 'warning',
      confirmButtonText: t('确定'),
      cancelButtonText: t('取消')
    })

    streamStopping.value = true
    const res = await stopStreamTask({
      taskId: currentMediaStream.value.taskStreamSn,
      lssId: currentMediaStream.value.lssId
    })
    if (res.success) {
      ElMessage.success(t('推流任务已停止'))
      // 更新当前流的状态
      currentMediaStream.value.status = '0'
      playbackInfo.value.isLive = false
      getList()
    } else {
      ElMessage.error(res.errMessage || t('停止失败'))
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('停止推流失败', error)
      ElMessage.error(t('停止推流失败'))
    }
  } finally {
    streamStopping.value = false
  }
}

// 停止推流
async function handleStopStream(row: LiveStreamDTO) {
  try {
    await ElMessageBox.confirm(t('确定要停止该推流任务吗？'), t('提示'), {
      type: 'warning',
      confirmButtonText: t('确定'),
      cancelButtonText: t('取消')
    })

    row._stopping = true
    const res = await stopStreamTask({ taskId: row.taskStreamSn, lssId: row.lssId })
    if (res.success) {
      ElMessage.success(t('推流任务已停止'))
      getList()
    } else {
      ElMessage.error(res.errMessage || t('停止失败'))
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('停止推流失败', error)
      ElMessage.error(t('停止推流失败'))
    }
  } finally {
    row._stopping = false
  }
}

// 从 playbackUrl 解析 videoId 和 customerDomain
function parsePlaybackUrl(playbackUrl: string): { videoId: string; customerDomain: string } | null {
  try {
    const url = new URL(playbackUrl)
    const customerDomain = url.hostname
    // URL 格式: https://domain/{videoId}/webRTC/play 或 https://domain/{videoId}/iframe
    const pathParts = url.pathname.split('/').filter(Boolean)
    if (pathParts.length > 0) {
      return { videoId: pathParts[0], customerDomain }
    }
  } catch (e) {
    console.error('解析 playbackUrl 失败', e)
  }
  return null
}

// 查看流媒体
async function handleViewCloudflare(row: LiveStreamDTO) {
  currentMediaStream.value = row

  // 同时填充表单数据，以便用户可以切换到编辑 tab
  Object.assign(form, {
    id: row.id,
    name: row.name,
    lssId: row.lssId || '',
    cameraId: row.cameraId || '',
    channelId: row.channelId,
    pushMethod: row.pushMethod || 'ffmpeg',
    commandTemplate: row.commandTemplate || '',
    timeoutSeconds: row.timeoutSeconds || 30,
    remark: row.remark || '',
    enabled: row.enabled
  })

  // 默认值
  let videoId = ''
  let customerDomain = 'customer-pj89kn2ke2tcuh19.cloudflarestream.com'

  // 优先从 playbackUrl 解析
  if (row.playbackUrl) {
    const parsed = parsePlaybackUrl(row.playbackUrl)
    if (parsed) {
      videoId = parsed.videoId
      customerDomain = parsed.customerDomain
    }
  }

  // 尝试获取播放信息
  if (row.streamSn) {
    try {
      const res = await getStreamPlayback(row.streamSn)
      if (res.success && res.data) {
        playbackInfo.value = {
          videoId: videoId || row.streamSn,
          customerDomain,
          hlsUrl: res.data.hlsUrl,
          whepUrl: res.data.whepUrl,
          isLive: res.data.isLive
        }
      } else {
        playbackInfo.value = {
          videoId: videoId || row.streamSn,
          customerDomain,
          isLive: false
        }
      }
    } catch (error) {
      console.error('获取播放信息失败', error)
      playbackInfo.value = {
        videoId: videoId || row.streamSn,
        customerDomain,
        isLive: false
      }
    }
  } else if (videoId) {
    playbackInfo.value = {
      videoId,
      customerDomain,
      isLive: false
    }
  }

  activeDrawerTab.value = 'play'
  drawerVisible.value = true

  // 自动加载 PTZ 预置位和能力信息
  if (hasCameraConnection()) {
    loadPTZPresets()
    loadCameraCapabilities()
  }

  // 加载时间轴配置
  loadTimelineConfig()
}

// 播放控制
function handlePlay() {
  playerRef.value?.play()
}

function handlePause() {
  playerRef.value?.pause()
}

function handlePlayerStop() {
  playerRef.value?.stop()
}

function handleScreenshot() {
  playerRef.value?.screenshot()
}

function handleFullscreen() {
  playerRef.value?.fullscreen()
}

// PTZ 控制 (使用直连 PTZ API)
// PTZ 方向映射
const directionToAction: Record<string, PTZAction> = {
  UP: 'up',
  DOWN: 'down',
  LEFT: 'left',
  RIGHT: 'right',
  STOP: 'stop'
}

async function handlePTZ(direction: string) {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }

  try {
    const command = directionToAction[direction] || 'stop'
    const res = await ptzControl({ cameraId, command, speed: ptzSpeed.value })
    if (!res.success) {
      console.error('PTZ 控制失败', res.errMsg)
    }
  } catch (error) {
    console.error('PTZ 控制失败', error)
  }
}

async function handlePTZStop() {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) return

  try {
    await ptzControl({ cameraId, command: 'stop' })
  } catch (error) {
    console.error('PTZ 停止失败', error)
  }
}

// 缩放控制
function formatZoomTooltip(val: number) {
  if (val === 0) return t('停止')
  return val > 0 ? `${t('放大')} ${val}` : `${t('缩小')} ${Math.abs(val)}`
}

async function handleZoomChange(val: number) {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) return

  if (val === 0) {
    await ptzControl({ cameraId, command: 'stop' })
    return
  }

  const command = val > 0 ? 'zoom_in' : 'zoom_out'
  await ptzControl({ cameraId, command, speed: Math.abs(val) })
}

async function handleZoomRelease() {
  zoomValue.value = 0
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) return
  await ptzControl({ cameraId, command: 'stop' })
}

// 缩放按钮控制
async function handleZoomIn() {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }
  try {
    const res = await ptzControl({ cameraId, command: 'zoom_in', speed: ptzSpeed.value })
    if (!res.success) {
      console.error('Zoom in 失败', res.errMsg)
    }
  } catch (error) {
    console.error('Zoom in 失败', error)
  }
}

async function handleZoomOut() {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }
  try {
    const res = await ptzControl({ cameraId, command: 'zoom_out', speed: ptzSpeed.value })
    if (!res.success) {
      console.error('Zoom out 失败', res.errMsg)
    }
  } catch (error) {
    console.error('Zoom out 失败', error)
  }
}

// ==================== PTZ 直连 API ====================

// 检查摄像头连接配置
function hasCameraConnection(): boolean {
  return !!currentMediaStream.value?.cameraId
}

// 加载 PTZ 预置位 (通过 camera API)
async function loadPTZPresets() {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }

  presetsLoading.value = true
  try {
    const res = await presetList({ cameraId })
    if (res.code === 200 && res.data) {
      ptzPresetList.value = res.data as PresetInfo[]
    } else {
      ptzPresetList.value = []
      if (!res.success) {
        ElMessage.error(res.errMsg || t('加载预置位失败'))
      }
    }
  } catch (error) {
    console.error('加载 PTZ 预置位失败', error)
    ptzPresetList.value = []
  } finally {
    presetsLoading.value = false
  }
}

// 跳转到 PTZ 预置位 (通过 camera API)
async function handleGotoPTZPreset(preset: PresetInfo) {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先配置摄像头连接'))
    return
  }

  try {
    activePresetId.value = preset.id
    const res = await presetGoto({ cameraId, presetId: parseInt(preset.id) })
    if (res.code === 200) {
      ElMessage.success(`${t('已跳转到预置位')}: ${preset.name || preset.id}`)
    } else {
      ElMessage.error(res.errMsg || t('跳转失败'))
    }
  } catch (error) {
    console.error('跳转 PTZ 预置位失败', error)
    ElMessage.error(t('跳转失败'))
  }
}

// 编辑预置位 (设置按钮)
function handleEditPreset(preset: PTZPresetInfo) {
  ElMessage.info(`${t('设置预置位')}: ${preset.name || preset.id}`)
  // TODO: 打开预置位设置对话框
}

// 删除预置位
async function handleDeletePreset(preset: PTZPresetInfo) {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先配置摄像头连接'))
    return
  }

  try {
    await ElMessageBox.confirm(`${t('确定删除预置位')} "${preset.name || `Preset ${preset.id}`}"?`, t('删除确认'), {
      type: 'warning'
    })

    const res = await presetRemove({ cameraId, presetId: parseInt(preset.id) })
    if (res.success) {
      ElMessage.success(t('删除成功'))
      // 刷新预置位列表
      loadPTZPresets()
    } else {
      ElMessage.error(res.errMsg || t('删除失败'))
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除预置位失败', error)
      ElMessage.error(t('删除失败'))
    }
  }
}

// 加载摄像头能力信息 (通过 camera API)
async function loadCameraCapabilities() {
  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    return
  }

  capabilitiesLoading.value = true
  try {
    const res = await getPTZCapabilities({ cameraId })
    if (res.success && res.data) {
      cameraCapabilities.value = res.data as PTZCapabilities
    } else {
      cameraCapabilities.value = null
    }
  } catch (error) {
    console.error('加载摄像头能力失败', error)
    cameraCapabilities.value = null
  } finally {
    capabilitiesLoading.value = false
  }
}

// ==================== 时间轴功能 ====================

// 格式化时间轴时间 (秒 -> m:ss)
function formatTimelineTime(seconds: number): string {
  const mins = Math.floor(seconds / 60)
  const secs = seconds % 60
  return `${mins}:${secs.toString().padStart(2, '0')}`
}

// 开始拖拽点
function startDragPoint(e: MouseEvent, point: TimelinePoint) {
  // 只响应鼠标左键
  if (e.button !== 0) return

  draggingPoint.value = point
  selectedPoint.value = point

  // 添加全局事件监听
  document.addEventListener('mousemove', handleDragMove)
  document.addEventListener('mouseup', handleDragEnd)

  // 防止文本选择
  e.preventDefault()
}

// 拖拽移动
function handleDragMove(e: MouseEvent) {
  if (!draggingPoint.value) return

  const track = timelineTrackRef.value
  if (!track) return

  const rect = track.getBoundingClientRect()
  const x = e.clientX - rect.left
  const percent = Math.max(0, Math.min(1, x / rect.width))
  const time = Math.round(percent * timelineDuration.value)

  // 更新点的时间位置
  draggingPoint.value.time = time
}

// 结束拖拽
function handleDragEnd() {
  if (draggingPoint.value) {
    // 重新排序并保存
    sortAndRenumberPoints()
    saveTimelineConfig()
    draggingPoint.value = null
  }

  // 移除全局事件监听
  document.removeEventListener('mousemove', handleDragMove)
  document.removeEventListener('mouseup', handleDragEnd)
}

// 添加关键点
function addTimelinePoint(time?: number) {
  const newId = timelinePoints.value.length > 0 ? Math.max(...timelinePoints.value.map((p) => p.id)) + 1 : 1
  const newTime = time ?? Math.round(timelineDuration.value / 2)

  // 确保时间在有效范围内
  const clampedTime = Math.max(0, Math.min(newTime, timelineDuration.value))

  const newPoint: TimelinePoint = {
    id: newId,
    time: clampedTime,
    active: false
  }

  timelinePoints.value.push(newPoint)
  sortAndRenumberPoints()
  saveTimelineConfig()
  selectPoint(newPoint)
}

// 按时间排序并重新编号
function sortAndRenumberPoints() {
  timelinePoints.value.sort((a, b) => a.time - b.time)
  timelinePoints.value.forEach((point, index) => {
    point.id = index + 1
  })
}

// 选中点
function selectPoint(point: TimelinePoint) {
  selectedPoint.value = point

  // 如果已有预置位，跳转到该位置
  const cameraId = currentMediaStream.value?.cameraId
  if (point.presetId && cameraId) {
    presetGoto({ cameraId, presetId: point.presetId }).then((res) => {
      if (res.success) {
        ElMessage.success(`${t('已跳转到')}: ${point.presetName || `Point ${point.id}`}`)
      }
    })
  }
}

// 保存当前点的预置位
async function saveCurrentPoint() {
  if (!selectedPoint.value) return

  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }

  const point = selectedPoint.value
  // 使用时间轴专用的预置位ID范围 (100+)
  const presetIdNum = point.presetId || 100 + point.id
  const presetName = `Timeline_${point.id}`

  savingPreset.value = true
  try {
    const res = await presetSet({ cameraId, presetId: presetIdNum, presetName })
    if (res.success) {
      point.presetId = presetIdNum
      point.presetName = presetName
      point.active = true
      saveTimelineConfig()
      ElMessage.success(`${t('已保存')} ${presetName}`)
    } else {
      ElMessage.error(res.errMsg || t('保存失败'))
    }
  } catch (error) {
    console.error('保存预置位失败', error)
    ElMessage.error(t('保存失败'))
  } finally {
    savingPreset.value = false
  }
}

// 删除选中的点
function deleteSelectedPoint() {
  if (!selectedPoint.value) return

  const index = timelinePoints.value.findIndex((p) => p.id === selectedPoint.value!.id)
  if (index !== -1) {
    timelinePoints.value.splice(index, 1)
    sortAndRenumberPoints()
    saveTimelineConfig()
    selectedPoint.value = null
    ElMessage.success(t('已删除'))
  }
}

// 关联已有预置位
function handleLinkPreset(presetId: string | null) {
  if (!selectedPoint.value || !presetId) {
    linkPresetId.value = null
    return
  }

  const preset = ptzPresetList.value.find((p) => p.id === presetId)
  if (preset) {
    selectedPoint.value.presetId = parseInt(preset.id)
    selectedPoint.value.presetName = preset.name || `Preset ${preset.id}`
    selectedPoint.value.active = true
    saveTimelineConfig()
    ElMessage.success(`${t('已关联')}: ${selectedPoint.value.presetName}`)
    linkPresetId.value = null
  }
}

// 自动映射：点1-N 对应 Preset 1-N
function autoLinkPresets() {
  if (ptzPresetList.value.length === 0) {
    ElMessage.warning(t('暂无可用预置位'))
    return
  }

  // 按ID排序预置位列表（取前几个数字小的）
  const sortedPresets = [...ptzPresetList.value]
    .filter((p) => !isNaN(parseInt(p.id)))
    .sort((a, b) => parseInt(a.id) - parseInt(b.id))

  let linkedCount = 0
  timelinePoints.value.forEach((point, index) => {
    if (index < sortedPresets.length) {
      const preset = sortedPresets[index]
      point.presetId = parseInt(preset.id)
      point.presetName = preset.name || `Preset ${preset.id}`
      point.active = true
      linkedCount++
    }
  })

  if (linkedCount > 0) {
    saveTimelineConfig()
    ElMessage.success(`${t('已映射')} ${linkedCount} ${t('个点位')}`)
  } else {
    ElMessage.warning(t('没有可映射的点位'))
  }
}

// 右键菜单删除点
function handlePointContextMenu(e: MouseEvent, point: TimelinePoint) {
  ElMessageBox.confirm(`${t('确定删除')} "${point.presetName || `Point ${point.id}`}"?`, t('删除确认'), {
    type: 'warning'
  })
    .then(() => {
      const index = timelinePoints.value.findIndex((p) => p.id === point.id)
      if (index !== -1) {
        timelinePoints.value.splice(index, 1)
        sortAndRenumberPoints()
        saveTimelineConfig()
        if (selectedPoint.value?.id === point.id) {
          selectedPoint.value = null
        }
        ElMessage.success(t('已删除'))
      }
    })
    .catch(() => {})
}

// 时长改变时重新分配点的时间
function handleDurationChange() {
  // 如果有点超出新时长，调整它们
  timelinePoints.value.forEach((point) => {
    if (point.time > timelineDuration.value) {
      point.time = timelineDuration.value
    }
  })
  saveTimelineConfig()
}

// 进度条动画帧ID
let progressAnimationId: number | null = null
let loopStartTime = 0

// 播放巡航
async function playTimeline() {
  const activePoints = timelinePoints.value.filter((p) => p.active).sort((a, b) => a.time - b.time)
  if (activePoints.length === 0) {
    ElMessage.warning(t('请先设置至少一个点位'))
    return
  }

  const cameraId = currentMediaStream.value?.cameraId
  if (!cameraId) {
    ElMessage.warning(t('请先选择直播流'))
    return
  }

  isTimelinePlaying.value = true
  timelineProgress.value = 0
  selectedPoint.value = null // 清除选中状态
  timelinePlayAbort = new AbortController()

  const totalDuration = timelineDuration.value * 1000 // 转为毫秒

  // 启动进度条动画（持续更新）
  function updateProgress() {
    if (!isTimelinePlaying.value) return
    const elapsed = Date.now() - loopStartTime
    const progress = Math.min((elapsed / totalDuration) * 100, 100)
    timelineProgress.value = progress
    progressAnimationId = requestAnimationFrame(updateProgress)
  }

  try {
    // 循环播放（do-while 支持循环模式）
    do {
      loopStartTime = Date.now()
      timelineProgress.value = 0

      // 启动/重启进度条动画
      if (progressAnimationId) {
        cancelAnimationFrame(progressAnimationId)
      }
      progressAnimationId = requestAnimationFrame(updateProgress)

      // 播放各个点
      for (let i = 0; i < activePoints.length; i++) {
        if (timelinePlayAbort?.signal.aborted) break

        const point = activePoints[i]
        const targetTime = (point.time / timelineDuration.value) * totalDuration
        const waitTime = targetTime - (Date.now() - loopStartTime)

        // 等待到达该点的时间
        if (waitTime > 0) {
          await sleep(waitTime, timelinePlayAbort.signal)
        }

        if (timelinePlayAbort?.signal.aborted) break

        // 跳转到该预置位
        if (point.presetId) {
          await presetGoto({ cameraId, presetId: point.presetId })
        }
      }

      // 等待剩余时间
      const remainingTime = totalDuration - (Date.now() - loopStartTime)
      if (remainingTime > 0 && !timelinePlayAbort?.signal.aborted) {
        await sleep(remainingTime, timelinePlayAbort.signal)
      }
    } while (isLoopEnabled.value && !timelinePlayAbort?.signal.aborted)

    // 播放完成（非循环模式或被停止）
    if (!timelinePlayAbort?.signal.aborted) {
      timelineProgress.value = 100
      await sleep(500)
      ElMessage.success(t('巡航完成'))
    }
  } catch (error) {
    if ((error as Error).name !== 'AbortError') {
      console.error('巡航播放失败', error)
      ElMessage.error(t('巡航播放失败'))
    }
  } finally {
    // 停止进度条动画
    if (progressAnimationId) {
      cancelAnimationFrame(progressAnimationId)
      progressAnimationId = null
    }
    isTimelinePlaying.value = false
    timelineProgress.value = 0
    timelinePlayAbort = null
  }
}

// 停止巡航
function stopTimeline() {
  // 停止进度条动画
  if (progressAnimationId) {
    cancelAnimationFrame(progressAnimationId)
    progressAnimationId = null
  }
  if (timelinePlayAbort) {
    timelinePlayAbort.abort()
    timelinePlayAbort = null
  }
  isTimelinePlaying.value = false
  timelineProgress.value = 0
}

// 带取消功能的 sleep
function sleep(ms: number, signal?: AbortSignal): Promise<void> {
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(resolve, ms)
    signal?.addEventListener('abort', () => {
      clearTimeout(timeout)
      reject(new DOMException('Aborted', 'AbortError'))
    })
  })
}

// 保存时间轴到 localStorage
function saveTimelineConfig() {
  const config = {
    duration: timelineDuration.value,
    points: timelinePoints.value,
    streamSn: currentMediaStream.value?.streamSn
  }
  localStorage.setItem(TIMELINE_STORAGE_KEY, JSON.stringify(config))
}

// 从 localStorage 加载时间轴
function loadTimelineConfig() {
  const saved = localStorage.getItem(TIMELINE_STORAGE_KEY)
  if (saved) {
    try {
      const config = JSON.parse(saved)
      // 只有当 streamSn 匹配时才加载
      if (config.streamSn === currentMediaStream.value?.streamSn) {
        timelineDuration.value = config.duration || 180
        timelinePoints.value = config.points || []
        selectedPoint.value = null
      } else {
        // 不同的流，重置时间轴
        resetTimeline()
      }
    } catch {
      resetTimeline()
    }
  }
}

// 重置时间轴
function resetTimeline() {
  timelineDuration.value = 180
  timelinePoints.value = []
  selectedPoint.value = null
  isTimelinePlaying.value = false
  timelineProgress.value = 0
}

function handleSizeChange(val: number) {
  pageSize.value = val
  currentPage.value = 1
  getList()
}

function handleCurrentChange(val: number) {
  currentPage.value = val
  getList()
}

onMounted(async () => {
  // 读取 URL 查询参数
  const queryCameraId = route.query.cameraId as string
  const queryAction = route.query.action as string

  if (queryCameraId) {
    searchForm.cameraId = queryCameraId
  }

  // 先加载选项数据
  await loadOptions()
  getList()

  // 如果是创建操作，自动打开新增抽屉
  if (queryAction === 'create') {
    handleAdd()

    // 如果提供了 cameraId，尝试查找摄像头信息以自动填充 lssId
    if (queryCameraId) {
      try {
        const res = await adminListCameras({ cameraId: queryCameraId, size: 1 })
        if (res.success && res.data?.list?.length > 0) {
          const camera = res.data.list[0]
          if (camera.lssId) {
            form.lssId = camera.lssId
            // lssId 变化会触发 watch，加载该 LSS 下的摄像头列表
            // 等待摄像头列表加载完成后再设置 cameraId
            setTimeout(() => {
              form.cameraId = queryCameraId
            }, 500)
          }
        }
      } catch (error) {
        console.error('获取摄像头信息失败', error)
      }
    }
  }
})
</script>

<style lang="scss" scoped>
.page-container {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}

.command-template-container {
  padding: 0 20px;
}

.search-form {
  flex-shrink: 0;
  margin-bottom: 16px;
  padding: 16px 16px 4px 16px;
  background: #f5f7fa;

  :deep(.el-form-item) {
    margin-bottom: 12px;
    margin-right: 16px;
  }

  :deep(.el-input),
  :deep(.el-select) {
    width: 180px;
  }
}

.table-wrapper {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.pagination-container {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding-top: 16px;
}

:deep(.el-table) {
  --el-table-row-hover-bg-color: #f0f0ff;

  .el-table__row--striped td.el-table__cell {
    background-color: #f8f9fc;
  }

  .el-table__header th {
    background-color: #f5f7fa;
    color: #333;
    font-weight: 600;
  }
}

// 合并抽屉样式
.combined-drawer {
  :deep(.el-drawer__body) {
    padding: 0;
    display: flex;
    flex-direction: column;
    height: 100%;
  }
}

.drawer-content {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.drawer-tabs {
  flex-shrink: 0;
  padding: 0 20px;
  border-bottom: 1px solid #e5e7eb;

  :deep(.el-tabs__header) {
    margin: 0;
  }

  :deep(.el-tabs__nav-wrap::after) {
    display: none;
  }

  :deep(.el-tabs__item) {
    font-size: 15px;
    padding: 0 20px;
    height: 48px;
    line-height: 48px;
  }
}

.tab-content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.edit-content {
  .drawer-body {
    flex: 1;
    overflow-y: auto;
  }
}

.play-content {
  //background-color: #f5f7fa;
}

.drawer-header {
  flex-shrink: 0;
  padding: 16px 20px;
  font-size: 16px;
  font-weight: 500;
  color: #303133;
  border-bottom: 1px solid #e5e7eb;
}

.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.stream-form {
  :deep(.el-form-item) {
    margin-bottom: 18px;
  }

  :deep(.el-form-item__label) {
    color: #606266;
    font-size: 14px;
  }
}

.drawer-footer {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding: 12px 20px;
  border-top: 1px solid #e5e7eb;
  gap: 12px;
}

// 流媒体播放抽屉样式
.media-drawer {
  :deep(.el-drawer__body) {
    padding: 0;
    display: flex;
    flex-direction: column;
    height: 100%;
    background-color: #f5f7fa;
    position: relative;
  }
}

.drawer-close-btn {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  // background-color: rgba(0, 0, 0, 0.5);
  // border-radius: 50%;
  cursor: pointer;
  z-index: 10;
  color: #303133;
  transition: all 0.2s;

  // &:hover {
  //   background-color: rgba(0, 0, 0, 0.7);
  // }
}

.media-drawer-content {
  display: flex;
  height: 100%;
  padding: 20px;
  gap: 8px;
  overflow: hidden;
}

// 左侧视频区域
.video-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background-color: #e1e1e1;
  // border-radius: 0px;
  overflow: hidden;
  // box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);

  .video-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    background-color: #f5f7fa;

    .header-left {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .title {
      font-size: 16px;
      font-weight: 600;
      color: #303133;
    }
  }

  .player-container {
    flex: 1;
    min-height: 0;
    background-color: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;

    .player-placeholder {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      color: #909399;

      p {
        margin-top: 15px;
        font-size: 14px;
      }
    }

    .stream-control-overlay {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 10;

      .el-button {
        font-size: 18px;
        padding: 16px 32px;
        border-radius: 0;
      }
    }
  }

  .player-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    background: #e5e7eb;
  }
}

// 时间轴容器
.timeline-container {
  background: #1a1a1a;
  padding: 12px 16px;
  flex-shrink: 0;

  .timeline-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;

    .timeline-label {
      color: #fff;
      font-size: 13px;
      font-weight: 500;
    }

    :deep(.el-select) {
      .el-input__wrapper {
        background-color: #333;
        border-color: #444;
      }

      .el-input__inner {
        color: #fff;
      }
    }
  }

  .timeline-track {
    position: relative;
    height: 32px;
    background: linear-gradient(to right, #374151, #374151);
    border-radius: 4px;
    margin-bottom: 8px;

    &.is-playing {
      cursor: not-allowed;

      .timeline-point {
        cursor: not-allowed;
        pointer-events: none;
      }
    }

    .timeline-progress {
      position: absolute;
      top: 0;
      left: 0;
      height: 100%;
      background: linear-gradient(to right, #dc2626, #f87171);
      border-radius: 4px 0 0 4px;
      pointer-events: none;
      transition: width 0.3s ease;
    }

    .timeline-point {
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      width: 24px;
      height: 24px;
      border-radius: 50%;
      background: #6b7280; // 未激活 - 灰色
      border: 2px solid #fff;
      cursor: grab;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 11px;
      color: #fff;
      font-weight: bold;
      z-index: 5;
      transition: all 0.2s;

      &:hover {
        transform: translate(-50%, -50%) scale(1.15);

        .point-tooltip {
          opacity: 1;
          visibility: visible;
        }
      }

      &.active {
        background: #22c55e; // 激活 - 绿色
      }

      &.selected {
        box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.5);
        transform: translate(-50%, -50%) scale(1.2);
        z-index: 10;

        .point-tooltip {
          opacity: 1;
          visibility: visible;
        }
      }

      &.dragging {
        cursor: grabbing;
        transform: translate(-50%, -50%) scale(1.3);
        box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.6);
        z-index: 20;
        transition: none; // 拖拽时禁用过渡动画

        .point-tooltip {
          opacity: 1;
          visibility: visible;
        }
      }

      .point-label {
        line-height: 1;
      }

      .point-tooltip {
        position: absolute;
        bottom: calc(100% + 8px);
        left: 50%;
        transform: translateX(-50%);
        background: rgba(0, 0, 0, 0.85);
        color: #fff;
        padding: 6px 10px;
        border-radius: 4px;
        font-size: 11px;
        white-space: nowrap;
        opacity: 0;
        visibility: hidden;
        transition: all 0.2s;
        pointer-events: none;

        .point-time {
          color: #9ca3af;
          font-size: 10px;
          margin-top: 2px;
        }

        &::after {
          content: '';
          position: absolute;
          top: 100%;
          left: 50%;
          transform: translateX(-50%);
          border: 5px solid transparent;
          border-top-color: rgba(0, 0, 0, 0.85);
        }
      }
    }
  }

  .timeline-scale {
    display: flex;
    justify-content: space-between;
    padding: 0 2px;

    .scale-mark {
      font-size: 10px;
      color: #6b7280;
    }
  }

  .timeline-point-panel {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    padding: 10px 12px;
    background: #2a2a2a;
    border-radius: 4px;
    flex-wrap: wrap;

    .panel-label {
      color: #d1d5db;
      font-size: 12px;
      flex: 1;
      min-width: 100%;
    }
  }

  .timeline-auto-link {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 8px 12px;
    background: #1f1f1f;
    border-radius: 4px;

    .auto-link-hint {
      color: #6b7280;
      font-size: 11px;
    }
  }
}

// 右侧控制面板
.control-panel {
  width: 280px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;

  .ptz-collapse {
    border: none;

    :deep(.el-collapse-item) {
      margin-bottom: 8px;
      background-color: #fff;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);

      .el-collapse-item__header {
        padding: 0 16px;
        height: 44px;
        border-bottom: 1px solid #e5e7eb;
        background-color: #f5f7fa;

        &.is-active {
          border-bottom-color: #e5e7eb;
        }
      }

      .el-collapse-item__wrap {
        border-bottom: none;
      }

      .el-collapse-item__content {
        padding: 0;
        // padding-bottom: 12px;
      }
    }

    .collapse-title {
      font-size: 14px;
      font-weight: 600;
      color: #303133;
    }

    .collapse-title-with-action {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
      padding-right: 8px;

      .collapse-title {
        font-size: 14px;
        font-weight: 600;
        color: #303133;
      }
    }
  }

  .panel-section {
    background-color: #fff;
    border-radius: 8px;
    padding: 16px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);

    .section-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 14px;
      font-weight: 600;
      color: #303133;
      margin-bottom: 12px;
      padding-bottom: 8px;
      border-bottom: 1px solid #e5e7eb;
    }
  }
}

// PTZ 方向控制网格
.ptz-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-bottom: 12px;
}

.ptz-btn {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  color: #606266;

  &:hover {
    background-color: #ecf5ff;
    border-color: #4f46e5;
    color: #4f46e5;
  }

  &:active {
    background-color: #4f46e5;
    color: #fff;
  }

  .el-icon {
    font-size: 18px;
  }

  &.ptz-center {
    background-color: #e5e7eb;

    &:hover {
      background-color: #4f46e5;
      color: #fff;
    }
  }
}

// 缩放按钮
.zoom-buttons {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-bottom: 12px;

  .el-button {
    background-color: #f5f7fa;
    border-color: #dcdfe6;
    color: #606266;

    &:hover {
      background-color: #ecf5ff;
      border-color: #4f46e5;
      color: #4f46e5;
    }
  }
}

// 速度滑块
.speed-slider {
  display: flex;
  align-items: center;
  gap: 12px;

  .label {
    font-size: 12px;
    color: #606266;
    flex-shrink: 0;
  }

  .value {
    font-size: 12px;
    color: #4f46e5;
    width: 30px;
    text-align: right;
  }

  :deep(.el-slider) {
    flex: 1;
  }
}

// 预置位区域
.preset-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 250px;
  overflow-y: auto;
}

.preset-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background-color: #fff;
  border-bottom: 1px solid #ebeef5;
  cursor: default;
  transition: all 0.2s;

  &:hover {
    background-color: #f5f7fa;

    .preset-actions {
      opacity: 1;
      visibility: visible;
    }
  }

  &.active {
    background-color: #ecf5ff;

    .preset-index {
      background-color: #4f46e5;
      color: #fff;
    }

    .preset-name {
      color: #4f46e5;
      font-weight: 500;
    }
  }

  .preset-index {
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #f0f0f0;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 500;
    color: #606266;
    flex-shrink: 0;
  }

  .preset-name {
    flex: 1;
    font-size: 13px;
    color: #606266;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .preset-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    opacity: 0;
    visibility: hidden;
    transition: all 0.2s;

    .action-icon {
      width: 20px;
      height: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      color: #909399;
      transition: color 0.2s;

      &:hover {
        color: #4f46e5;
      }

      &.delete:hover {
        color: #f56c6c;
      }
    }
  }
}

// 摄像头信息区域
.camera-info-content {
  min-height: 60px;
}

.info-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px dashed #e5e7eb;

  &:last-child {
    border-bottom: none;
  }
}

.info-label {
  font-size: 12px;
  color: #909399;
}

.info-value {
  font-size: 12px;
  color: #303133;
  font-weight: 500;
}
</style>
