<template>
  <div class="map-mgr-page">
    <el-tabs v-model="activeTab" type="border-card" class="map-mgr-tabs admin-tabs">
      <el-tab-pane label="服务器地图" name="maps">
        <div class="mm-section">
          <div class="map-mgr-header">
            <span class="subtitle">
              统一维护后台所有地图资源（固定文件夹 / JSON），可新增 / 使用 / 重命名 / 编辑 / 删除。
            </span>
            <div class="actions">
              <el-button :loading="loading" @click="refresh">刷新</el-button>
              <el-button type="primary" @click="onCreate">新增地图</el-button>
            </div>
          </div>

          <el-alert
            v-if="directory"
            class="dir-tip"
            type="info"
            :closable="false"
            show-icon
          >
            <template #title>
              地图文件夹：<code>{{ directory }}</code>
              <span v-if="currentName"> · 当前使用：<strong>{{ currentName }}</strong></span>
              <span v-else> · 当前未设置默认使用地图</span>
            </template>
          </el-alert>

          <div class="mm-body">
            <el-card shadow="never" class="mm-list-card">
              <el-table
                ref="tableRef"
                v-loading="loading"
                :data="maps"
                class="map-table"
                border
                highlight-current-row
                row-key="name"
                :row-class-name="rowClassName"
                empty-text="固定文件夹内还没有地图，点击右上角「新增地图」创建。"
                @row-click="onRowClick"
              >
                <el-table-column label="地图名称" min-width="180">
                  <template #default="{ row }">
                    <span class="map-name">{{ row.name }}</span>
                    <el-tag v-if="row.isCurrent" size="small" type="success" effect="dark" class="current-tag">
                      使用中
                    </el-tag>
                  </template>
                </el-table-column>
                <el-table-column label="修改时间" prop="modified" width="170" />
                <el-table-column label="操作" width="260" align="right">
                  <template #default="{ row }">
                    <el-button
                      size="small"
                      type="primary"
                      plain
                      :disabled="row.isCurrent"
                      :loading="busyName === row.name"
                      @click.stop="onUse(row)"
                    >
                      {{ row.isCurrent ? '使用中' : '使用' }}
                    </el-button>
                    <el-button size="small" @click.stop="onRename(row)">重命名</el-button>
                    <el-button size="small" @click.stop="onEdit(row)">编辑</el-button>
                    <el-button size="small" type="danger" plain @click.stop="onDelete(row)">删除</el-button>
                  </template>
                </el-table-column>
              </el-table>
            </el-card>

            <el-card shadow="never" class="mm-detail-card">
              <template v-if="!viewingName">
                <el-empty description="点击左侧地图行，右侧预览 JSON 配置（可按 {} 折叠）" />
              </template>
              <template v-else>
                <div class="mm-detail-head">
                  <div class="mm-detail-title">
                    <span class="map-name">{{ viewingName }}</span>
                    <el-tag v-if="viewingIsCurrent" size="small" type="success" effect="dark">使用中</el-tag>
                  </div>
                  <div v-if="viewingPath" class="mm-detail-meta">
                    <code>{{ viewingPath }}</code>
                  </div>
                </div>
                <div v-loading="contentLoading" class="mm-json-wrap">
                  <JsonFoldViewer v-if="viewingJsonRaw" :raw="viewingJsonRaw" />
                  <el-empty v-else-if="!contentLoading" description="未能加载地图配置" />
                </div>
              </template>
            </el-card>
          </div>
        </div>
      </el-tab-pane>

      <el-tab-pane label="多地图连接管理" name="connections">
        <MapConnectionPanel />
      </el-tab-pane>

      <el-tab-pane label="地图合并" name="merge">
        <MapMergePanel @merged="onMerged" />
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { TableInstance } from 'element-plus'
import { mapsApi, type MapListItem } from '@/api/mapEdit'
import JsonFoldViewer from '@/components/common/JsonFoldViewer.vue'
import MapConnectionPanel from '@/components/map-manage/MapConnectionPanel.vue'
import MapMergePanel from '@/components/map-manage/MapMergePanel.vue'

const router = useRouter()
const tableRef = ref<TableInstance>()

const activeTab = ref<'maps' | 'connections' | 'merge'>('maps')

function onMerged() {
  activeTab.value = 'maps'
  refresh()
}

const loading = ref(false)
const maps = ref<MapListItem[]>([])
const directory = ref('')
const currentName = ref('')
const busyName = ref('')

const viewingName = ref('')
const viewingPath = ref('')
const viewingJsonRaw = ref('')
const contentLoading = ref(false)

const viewingIsCurrent = computed(
  () => maps.value.find((m) => m.name === viewingName.value)?.isCurrent ?? false
)

function rowClassName({ row }: { row: MapListItem }) {
  const classes = []
  if (row.isCurrent) classes.push('current-row')
  if (row.name === viewingName.value) classes.push('viewing-row')
  return classes.join(' ')
}

async function loadMapContent(name: string) {
  contentLoading.value = true
  viewingJsonRaw.value = ''
  viewingPath.value = ''
  try {
    const r = await mapsApi.readContent(name)
    viewingPath.value = r.fileName
    viewingJsonRaw.value = r.content
  } catch (err) {
    ElMessage.error(`加载地图配置失败：${(err as Error).message}`)
  } finally {
    contentLoading.value = false
  }
}

async function selectMapRow(row: MapListItem) {
  viewingName.value = row.name
  await loadMapContent(row.name)
  await nextTick()
  tableRef.value?.setCurrentRow(row)
}

function onRowClick(row: MapListItem) {
  if (viewingName.value === row.name && viewingJsonRaw.value) return
  void selectMapRow(row)
}

async function refresh() {
  loading.value = true
  try {
    const r = await mapsApi.list()
    maps.value = r.maps
    directory.value = r.directory
    const cur = r.maps.find((m) => m.isCurrent)
    currentName.value = cur?.name ?? ''
    if (viewingName.value && !r.maps.some((m) => m.name === viewingName.value)) {
      viewingName.value = ''
      viewingJsonRaw.value = ''
      viewingPath.value = ''
      tableRef.value?.setCurrentRow(undefined)
    } else if (viewingName.value) {
      const row = r.maps.find((m) => m.name === viewingName.value)
      await loadMapContent(viewingName.value)
      if (row) {
        await nextTick()
        tableRef.value?.setCurrentRow(row)
      }
    }
  } catch (err) {
    ElMessage.error(`加载地图列表失败：${(err as Error).message}`)
  } finally {
    loading.value = false
  }
}

function onCreate() {
  // 新建地图：跳转地图编辑界面（空场景），保存时按时间默认命名。
  router.push({ path: '/admin/map-editor', query: { new: '1' } })
}

function onEdit(row: MapListItem) {
  // 编辑地图：跳转编辑界面并加载该地图，保存时默认替换原地图。
  router.push({ path: '/admin/map-editor', query: { map: row.name } })
}

async function onUse(row: MapListItem) {
  if (row.isCurrent) return
  busyName.value = row.name
  try {
    // 先做一次场景任务校验，给出更友好的明细提示；后端 use 仍会再次校验（防并发竞态）。
    const status = await mapsApi.sceneTaskStatus()
    if (status.hasTask) {
      const detail = status.busyCars
        .slice(0, 5)
        .map((c) => `${c.name}(#${c.id})：${c.reasons.join('、')}`)
        .join('\n')
      await ElMessageBox.alert(
        `场景内仍有 ${status.busyCount} 台车辆存在任务，无法切换当前地图。\n\n${detail}`,
        '禁止切换地图',
        { type: 'warning', confirmButtonText: '我知道了' }
      )
      return
    }

    await ElMessageBox.confirm(
      `确认将「${row.name}」设为当前项目默认使用的地图？切换会重新加载场景。`,
      '切换使用地图',
      { type: 'warning', confirmButtonText: '确认切换', cancelButtonText: '取消' }
    )

    const r = await mapsApi.use(row.name)
    ElMessage.success(`已切换到「${r.name}」：${r.sites} 站点 / ${r.tracks} 路径`)
    await refresh()
  } catch (err) {
    // 取消确认框不提示；其余（含后端 409 任务校验）提示错误文案。
    if (err === 'cancel' || err === 'close') return
    ElMessage.error(`切换失败：${(err as Error).message}`)
  } finally {
    busyName.value = ''
  }
}

const MAP_NAME_PATTERN = /^[^\\/:*?"<>|]+$/

async function onRename(row: MapListItem) {
  try {
    const r = await ElMessageBox.prompt('请输入新的地图名称', '重命名地图', {
      inputValue: row.name,
      inputPattern: MAP_NAME_PATTERN,
      inputErrorMessage: '名称不能包含 \\ / : * ? " < > | 等字符',
      confirmButtonText: '确定',
      cancelButtonText: '取消'
    })
    const to = (r.value ?? '').trim()
    if (!to || to === row.name) return

    busyName.value = row.name
    await mapsApi.rename(row.name, to)
    if (viewingName.value === row.name) viewingName.value = to
    ElMessage.success(`已重命名为「${to}」`)
    await refresh()
  } catch (err) {
    if (err === 'cancel' || err === 'close') return
    ElMessage.error(`重命名失败：${(err as Error).message}`)
  } finally {
    busyName.value = ''
  }
}

async function onDelete(row: MapListItem) {
  try {
    await ElMessageBox.confirm(
      `确认删除地图「${row.name}」？该操作会从固定文件夹中移除对应 JSON 文件，不可恢复。`,
      '删除地图',
      { type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消', confirmButtonClass: 'el-button--danger' }
    )
    await mapsApi.delete(row.name)
    if (viewingName.value === row.name) {
      viewingName.value = ''
      viewingJsonRaw.value = ''
      viewingPath.value = ''
      tableRef.value?.setCurrentRow(undefined)
    }
    ElMessage.success(`已删除「${row.name}」`)
    await refresh()
  } catch (err) {
    if (err === 'cancel' || err === 'close') return
    ElMessage.error(`删除失败：${(err as Error).message}`)
  }
}

onMounted(refresh)
</script>

<style scoped>
.map-mgr-page {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}

/* Tab 容器撑满主区；玻璃表面 / 选项卡样式由全局 .admin-tabs 提供（与场景管理一致），
 * 在星云紫等深色主题下给到不透明深紫底 + 白字，挡住 AppShell 的高亮光球，保证可读。 */
.map-mgr-tabs {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* 单个 Tab 内容区：纵向铺满，表格自适应高度 */
.mm-section {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
}

.map-mgr-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-shrink: 0;
}
.subtitle {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--mg-text-muted);
}
.dir-tip {
  flex-shrink: 0;
}
.dir-tip code {
  font-family: var(--mg-font-mono, monospace);
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--mg-veil-2);
  color: var(--mg-text-light);
}

.mm-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(420px, 1fr) 1.2fr;
  gap: 14px;
}

.mm-list-card,
.mm-detail-card {
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: rgba(30, 14, 55, 0.55) !important;
  border: 1px solid rgba(255, 255, 255, 0.08) !important;
  backdrop-filter: blur(12px);
}

.mm-list-card :deep(.el-card__body),
.mm-detail-card :deep(.el-card__body) {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
}

.map-table {
  flex: 1;
  min-height: 0;
}

.map-table :deep(.el-table__row) {
  cursor: pointer;
}
.map-name {
  font-weight: 500;
  color: var(--mg-text-light);
}
.current-tag {
  margin-left: 8px;
}
/* 「使用中」行高亮：用主题感知的成功色微透叠加，替换原固定浅绿 --el-color-success-light-9
   （在星云紫深底主题下「浅绿底 + 白字」几乎不可读）。深/浅两套主题下均保持清晰对比。 */
.map-table :deep(.current-row) > td.el-table__cell {
  background: rgba(var(--mg-status-success-rgb), 0.16) !important;
}
.map-table :deep(.current-row):hover > td.el-table__cell {
  background: rgba(var(--mg-status-success-rgb), 0.24) !important;
}

.map-table :deep(.viewing-row) > td.el-table__cell {
  background: rgba(var(--mg-accent-rgb, 120, 80, 200), 0.12) !important;
}

.mm-detail-head {
  flex-shrink: 0;
  margin-bottom: 10px;
}

.mm-detail-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.mm-detail-meta code {
  font-family: var(--mg-font-mono, monospace);
  font-size: 11px;
  color: var(--mg-text-muted);
  word-break: break-all;
}

.mm-json-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
</style>
