<template>
  <div class="data-center-page">
    <el-card v-loading="loading" shadow="never" class="page-card">
      <template #header>
        <div class="page-header">
          <div>
            <h2>{{ table?.title ?? title }}</h2>
            <p>
              读写 Simple3 工作目录 <code>Config/Signal</code>；改完后到信号交互进程点重新加载配置。
              点位为 BOOL 时按「字节 + 位」直接读写。
              <span v-if="table">
                （{{ table.fileName }}{{ table.exists ? '' : ' · 文件尚未创建，保存后写入' }}）
              </span>
            </p>
          </div>
          <div class="header-actions">
            <el-button type="primary" :disabled="loading" @click="openDialog()">新增</el-button>
            <el-button :icon="Refresh" :loading="loading" @click="load">刷新</el-button>
          </div>
        </div>
      </template>

      <el-alert
        v-if="loadError"
        type="warning"
        :title="loadError"
        show-icon
        :closable="false"
        style="margin-bottom: 12px"
      />

      <el-table :data="rows" border size="small" height="560" empty-text="暂无数据">
        <el-table-column
          v-for="col in columns"
          :key="col.key"
          :prop="col.key"
          :label="col.label"
          min-width="120"
          show-overflow-tooltip
        >
          <template #default="{ row }">
            <el-tag v-if="col.type === 'bool'" :type="truthy(row[col.key]) ? 'success' : 'info'" size="small">
              {{ truthy(row[col.key]) ? '是' : '否' }}
            </el-tag>
            <span v-else>{{ formatCell(row[col.key]) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" fixed="right">
          <template #default="{ row, $index }">
            <el-button size="small" link @click="openDialog(row, $index)">编辑</el-button>
            <el-button size="small" link type="danger" @click="removeRow($index)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <el-dialog v-model="dialogVisible" :title="editingIndex >= 0 ? '编辑' : '新增'" width="640px" destroy-on-close>
      <el-form label-width="148px">
        <template v-for="group in formGroups" :key="group.name || '_default'">
          <div v-if="group.name" class="form-group-title">{{ group.name }}</div>
          <el-form-item v-for="col in group.columns" :key="col.key" :label="col.label">
            <el-switch v-if="col.type === 'bool'" v-model="form[col.key]" />
            <el-select
              v-else-if="col.type === 'enum'"
              v-model="form[col.key]"
              filterable
              allow-create
              style="width: 100%"
            >
              <el-option v-for="opt in col.options ?? []" :key="opt" :label="opt" :value="opt" />
            </el-select>
            <el-input-number
              v-else-if="col.type === 'int'"
              v-model="form[col.key]"
              :controls="false"
              style="width: 100%"
            />
            <el-input v-else v-model="form[col.key]" />
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="commitDialog">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Refresh } from '@element-plus/icons-vue'
import { getSignalTable, saveSignalTable, type SignalColumn, type SignalTableDto } from '@/api/signalData'

const route = useRoute()
const title = computed(() => (route.meta.title as string | undefined) ?? '数据中心')
const tableId = computed(() => String(route.params.tableId ?? route.meta.tableId ?? ''))

const loading = ref(false)
const saving = ref(false)
const loadError = ref('')
const table = ref<SignalTableDto | null>(null)
const rows = ref<Record<string, unknown>[]>([])
const columns = computed<SignalColumn[]>(() => table.value?.columns ?? [])

const formGroups = computed(() => {
  const map = new Map<string, SignalColumn[]>()
  for (const col of columns.value) {
    const name = col.group?.trim() || ''
    if (!map.has(name)) map.set(name, [])
    map.get(name)!.push(col)
  }
  return [...map.entries()].map(([name, cols]) => ({ name, columns: cols }))
})

const dialogVisible = ref(false)
const editingIndex = ref(-1)
const form = reactive<Record<string, any>>({})

function truthy(v: unknown): boolean {
  return v === true || v === 'true' || v === 1 || v === '1'
}

function formatCell(v: unknown): string {
  if (v == null) return ''
  return String(v)
}

function emptyValue(col: SignalColumn): unknown {
  if (col.type === 'bool') return false
  if (col.type === 'int') return 0
  if (col.type === 'enum') return col.options?.[0] ?? ''
  return ''
}

function fillForm(src?: Record<string, unknown>) {
  for (const key of Object.keys(form)) delete form[key]
  for (const col of columns.value) {
    const raw = src?.[col.key]
    if (raw !== undefined && raw !== null) {
      form[col.key] = col.type === 'int' ? Number(raw) : raw
    } else {
      form[col.key] = emptyValue(col)
    }
  }
}

async function load() {
  if (!tableId.value) return
  loading.value = true
  loadError.value = ''
  try {
    const data = await getSignalTable(tableId.value)
    table.value = data
    rows.value = Array.isArray(data.rows) ? data.rows.map((r) => ({ ...r })) : []
    if (data.error) loadError.value = data.error
  } catch (e) {
    table.value = null
    rows.value = []
    loadError.value = e instanceof Error ? e.message : String(e)
  } finally {
    loading.value = false
  }
}

function openDialog(row?: Record<string, unknown>, index?: number) {
  editingIndex.value = index ?? -1
  fillForm(row)
  dialogVisible.value = true
}

async function persist(next: Record<string, unknown>[]) {
  saving.value = true
  try {
    const data = await saveSignalTable(tableId.value, next)
    table.value = data
    rows.value = Array.isArray(data.rows) ? data.rows.map((r) => ({ ...r })) : next
    ElMessage.success('已保存到信号配置 JSON')
  } finally {
    saving.value = false
  }
}

async function commitDialog() {
  const item: Record<string, unknown> = {}
  for (const col of columns.value) {
    let v = form[col.key]
    if (col.type === 'int') {
      const n = Number(v)
      v = Number.isFinite(n) ? Math.trunc(n) : 0
    } else if (col.type === 'bool') {
      v = truthy(v)
    } else {
      v = v == null ? '' : String(v)
    }
    item[col.key] = v
  }
  const next = rows.value.map((r) => ({ ...r }))
  if (editingIndex.value >= 0) next[editingIndex.value] = item
  else next.push(item)
  await persist(next)
  dialogVisible.value = false
}

async function removeRow(index: number) {
  const row = rows.value[index]
  const label = columns.value[0] ? String(row?.[columns.value[0].key] ?? index + 1) : String(index + 1)
  try {
    await ElMessageBox.confirm(`删除「${label}」？`, '确认', { type: 'warning' })
  } catch {
    return
  }
  const next = rows.value.filter((_, i) => i !== index)
  await persist(next)
}

watch(tableId, () => { void load() }, { immediate: true })
</script>

<style scoped>
.data-center-page {
  padding: 16px;
  height: 100%;
  box-sizing: border-box;
}
.page-card {
  height: 100%;
}
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.page-header h2 {
  margin: 0 0 4px;
  font-size: 18px;
}
.page-header p {
  margin: 0;
  color: var(--el-text-color-secondary);
  font-size: 13px;
  line-height: 1.5;
}
.page-header code {
  font-size: 12px;
}
.header-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.form-group-title {
  margin: 12px 0 8px;
  padding-bottom: 4px;
  font-weight: 600;
  font-size: 13px;
  color: var(--el-text-color-primary);
  border-bottom: 1px solid var(--el-border-color-lighter);
}
.form-group-title:first-child {
  margin-top: 0;
}
</style>
