<!-- =============================================================================
// 排查流程图 — 在线编辑器对话框
// =============================================================================
// 双栏布局(用户已确认 A 方案):
//   - 左 50%:CodeMirror JSON 源码(语法高亮 + 行号 + oneDark 主题)
//   - 右 50%:vue-json-pretty 树形预览(只读)
//   - 顶部:基本信息(名称/分类/标签/时间/难度)
//   - 底栏:格式化/复制/导出/取消/保存
// ============================================================================= -->
<template>
  <el-dialog
    :model-value="modelValue"
    @update:model-value="(v) => $emit('update:modelValue', v)"
    :title="dialogTitle"
    width="80%"
    top="5vh"
    :close-on-click-modal="false"
    :destroy-on-close="true"
  >
    <!-- ===== 顶部基本信息 ===== -->
    <div class="basic-info">
      <el-form :inline="true" size="small" label-width="70px">
        <el-form-item label="名称">
          <el-input v-model="form.name" placeholder="VPN 远程办公故障排查" style="width: 240px" :disabled="readonly" />
        </el-form-item>
        <el-form-item label="分类">
          <el-select v-model="form.category" placeholder="选择分类" style="width: 130px" :disabled="readonly">
            <el-option v-for="c in CATEGORY_OPTIONS" :key="c" :label="c" :value="c" />
          </el-select>
        </el-form-item>
        <el-form-item label="预估时间">
          <el-input-number v-model="form.estimated_time" :min="1" :max="120" size="small" :disabled="readonly" />
          <span class="suffix">分钟</span>
        </el-form-item>
        <el-form-item label="难度">
          <el-rate v-model="form.difficulty" :max="5" :disabled="readonly" />
        </el-form-item>
        <el-form-item label="标签">
          <el-select
            v-model="form.tags"
            multiple
            filterable
            allow-create
            default-first-option
            placeholder="按 Enter 添加"
            style="width: 240px"
            :disabled="readonly"
          />
        </el-form-item>
      </el-form>
    </div>

    <!-- ===== 双栏编辑区 ===== -->
    <div class="dual-pane">
      <!-- 左:JSON 源码编辑器 -->
      <div class="pane left-pane">
        <div class="pane-header">
          <span class="pane-title">📝 JSON 源码</span>
          <span class="pane-stats">
            节点 {{ stats.nodes }} · 决策 {{ stats.decisions }}
          </span>
        </div>
        <div class="pane-body">
          <codemirror
            v-model="jsonText"
            :options="cmOptions"
            :height="`${editorHeight}px`"
            :style="{ height: `${editorHeight}px` }"
            @change="onCodeChange"
            :readonly="readonly"
          />
        </div>
      </div>

      <!-- 右:树形预览 -->
      <div class="pane right-pane">
        <div class="pane-header">
          <span class="pane-title">🌳 树形预览</span>
          <span class="pane-stats">
            <el-tag v-if="parseOk" type="success" size="small">✅ JSON 有效</el-tag>
            <el-tag v-else type="danger" size="small">❌ {{ parseError }}</el-tag>
          </span>
        </div>
        <div class="pane-body">
          <div v-if="parseOk" class="tree-wrapper">
            <vue-json-pretty
              :data="parsedData"
              :show-length="true"
              :show-line="true"
              :path="rootPath"
              :deep="6"
            />
          </div>
          <div v-else class="tree-error">
            <p>❌ JSON 解析失败</p>
            <pre>{{ parseError }}</pre>
            <p class="hint">请检查左栏 JSON 语法,例如:</p>
            <ul>
              <li>末尾的逗号</li>
              <li>未闭合的引号或大括号</li>
              <li>未转义的字符</li>
            </ul>
          </div>
        </div>
      </div>
    </div>

    <!-- ===== 底栏按钮 ===== -->
    <template #footer>
      <div class="dialog-footer">
        <div class="footer-left">
          <el-button size="small" @click="handleFormat" :disabled="readonly">
            <el-icon><MagicStick /></el-icon>
            格式化
          </el-button>
          <el-button size="small" @click="handleCopy" :disabled="!parseOk">
            <el-icon><CopyDocument /></el-icon>
            复制
          </el-button>
          <el-button size="small" @click="handleExport" :disabled="!parseOk">
            <el-icon><Download /></el-icon>
            导出此条
          </el-button>
        </div>
        <div class="footer-right">
          <el-button size="small" @click="handleCancel">取消</el-button>
          <el-button
            size="small"
            type="primary"
            :disabled="!parseOk || readonly"
            :loading="saving"
            @click="handleSave"
          >
            <el-icon><Check /></el-icon>
            保存
          </el-button>
        </div>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
// =============================================================================
// imports
// =============================================================================
import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import { MagicStick, CopyDocument, Download, Check } from '@element-plus/icons-vue'
import { Codemirror } from 'vue-codemirror'
import { json } from '@codemirror/lang-json'
import { oneDark } from '@codemirror/theme-one-dark'
import VueJsonPretty from 'vue-json-pretty'
import 'vue-json-pretty/lib/styles.css'
import {
  formatJson,
  validateJson,
  countNodes,
  countDecisions,
  type TroubleshootingTemplate,
  type FlowchartNode,
} from '@/api/troubleshooting'

// =============================================================================
// props & emits
// =============================================================================
const props = defineProps<{
  modelValue: boolean
  template: TroubleshootingTemplate | null
  readonly?: boolean
  saving?: boolean
}>()

const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  save: [template: TroubleshootingTemplate]
  cancel: []
}>()

// =============================================================================
// 常量
// =============================================================================
const CATEGORY_OPTIONS = [
  'vpn', 'email', 'account', 'system', 'network',
  'printer', 'software', 'hardware', 'wecom', 'other',
]

const EMPTY_TEMPLATE: TroubleshootingTemplate = {
  name: '',
  category: 'system',
  description: '',
  estimated_time: 5,
  difficulty: 2,
  tags: [],
  root_node: {
    id: 'fc-new-1',
    type: 'step',
    label: '请修改此步骤',
    children: [],
  },
}

// =============================================================================
// 响应式状态
// =============================================================================
const form = reactive<TroubleshootingTemplate>({ ...EMPTY_TEMPLATE })
const jsonText = ref<string>('')
const parseOk = ref<boolean>(true)
const parseError = ref<string>('')
const parsedData = ref<TroubleshootingTemplate | null>(null)
const editorHeight = ref<number>(500)

// 编辑器配置
const cmOptions = {
  mode: 'application/json',
  theme: 'oneDark',
  lineNumbers: true,
  lineWrapping: true,
  tabSize: 2,
  indentUnit: 2,
  smartIndent: true,
  matchBrackets: true,
  autoCloseBrackets: true,
  foldGutter: true,
  gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
  extensions: [json(), oneDark],
}

// =============================================================================
// 计算属性
// =============================================================================
const dialogTitle = computed(() => {
  if (props.readonly) return `👁 预览: ${form.name || '未命名'}`
  return props.template?.id ? `✎ 编辑: ${form.name || '未命名'}` : '+ 新建流程图'
})

const stats = computed(() => ({
  nodes: parseOk.value && parsedData.value ? countNodes(parsedData.value.root_node) : 0,
  decisions: parseOk.value && parsedData.value ? countDecisions(parsedData.value.root_node) : 0,
}))

const rootPath = computed(() => 'root')

// =============================================================================
// watch
// =============================================================================
watch(
  () => props.template,
  (newTpl) => {
    if (newTpl) {
      Object.assign(form, newTpl)
      jsonText.value = formatJson(newTpl)
      onCodeChange()
    } else {
      Object.assign(form, EMPTY_TEMPLATE)
      jsonText.value = formatJson(EMPTY_TEMPLATE)
      onCodeChange()
    }
  },
  { immediate: true }
)

watch(jsonText, () => {
  // 实时同步到 form(让顶部表单跟着 JSON 变)
  if (parseOk.value && parsedData.value) {
    form.name = parsedData.value.name || form.name
    form.category = parsedData.value.category || form.category
    form.estimated_time = parsedData.value.estimated_time ?? form.estimated_time
    form.difficulty = parsedData.value.difficulty ?? form.difficulty
    form.tags = parsedData.value.tags || form.tags
  }
})

// =============================================================================
// 生命周期
// =============================================================================
function updateEditorHeight() {
  editorHeight.value = Math.max(window.innerHeight - 380, 300)
}

onMounted(() => {
  updateEditorHeight()
  window.addEventListener('resize', updateEditorHeight)
})

onUnmounted(() => {
  window.removeEventListener('resize', updateEditorHeight)
})

// =============================================================================
// 方法
// =============================================================================
function onCodeChange() {
  const result = validateJson(jsonText.value)
  if (result.ok) {
    parseOk.value = true
    parseError.value = ''
    parsedData.value = result.data
  } else {
    parseOk.value = false
    parseError.value = result.error
    parsedData.value = null
  }
}

function handleFormat() {
  if (parseOk.value && parsedData.value) {
    jsonText.value = formatJson(parsedData.value)
    ElMessage.success('JSON 已格式化')
  }
}

async function handleCopy() {
  try {
    await navigator.clipboard.writeText(jsonText.value)
    ElMessage.success('已复制到剪贴板')
  } catch {
    ElMessage.error('复制失败,请手动 Ctrl+C')
  }
}

function handleExport() {
  if (!parseOk.value || !parsedData.value) return
  const blob = new Blob([jsonText.value], { type: 'application/json' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `${(form.name || 'flowchart').replace(/\s+/g, '-')}.json`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  URL.revokeObjectURL(url)
  ElMessage.success('已导出')
}

function handleCancel() {
  emit('update:modelValue', false)
  emit('cancel')
}

function handleSave() {
  if (!parseOk.value || !parsedData.value) {
    ElMessage.error('JSON 无效,无法保存')
    return
  }
  // 合并:form 基本信息 + parsedData JSON 内容
  const finalTpl: TroubleshootingTemplate = {
    ...parsedData.value,
    name: form.name,
    category: form.category,
    description: form.description ?? parsedData.value.description,
    estimated_time: form.estimated_time,
    difficulty: form.difficulty,
    tags: form.tags,
  }
  emit('save', finalTpl)
}
</script>

<style scoped>
.basic-info {
  padding: 12px 0;
  background: #fafafa;
  border-radius: 6px;
  margin-bottom: 12px;
}

.basic-info :deep(.el-form-item) {
  margin-bottom: 0;
}

.basic-info .suffix {
  margin-left: 4px;
  color: #909399;
  font-size: 12px;
}

.dual-pane {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  height: 540px;
}

.pane {
  display: flex;
  flex-direction: column;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  overflow: hidden;
  background: white;
}

.pane-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: #f5f7fa;
  border-bottom: 1px solid #e4e7ed;
  font-size: 13px;
}

.pane-title {
  font-weight: 600;
  color: #303133;
}

.pane-stats {
  font-size: 12px;
  color: #909399;
}

.pane-body {
  flex: 1;
  overflow: auto;
  padding: 8px;
}

.right-pane .pane-body {
  background: #fafbfc;
}

.tree-wrapper {
  font-size: 13px;
}

.tree-error {
  color: #f56c6c;
  padding: 16px;
}

.tree-error pre {
  background: #fef0f0;
  padding: 8px;
  border-radius: 4px;
  font-size: 12px;
  white-space: pre-wrap;
}

.tree-error .hint {
  margin-top: 12px;
  color: #909399;
  font-size: 12px;
}

.tree-error ul {
  margin: 4px 0;
  padding-left: 20px;
  color: #909399;
  font-size: 12px;
}

.dialog-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.footer-left,
.footer-right {
  display: flex;
  gap: 8px;
}

:deep(.el-dialog__body) {
  padding: 16px 20px;
}

:deep(.CodeMirror) {
  height: 100%;
  font-family: 'Fira Code', 'Source Code Pro', monospace;
  font-size: 13px;
}
</style>
