<template>
  <section class="designer-shell-page" v-loading="loading">
    <header class="designer-topbar">
      <div class="designer-title">
        <span class="breadcrumb">{{ projectName || '项目' }} / 页面设计器</span>
        <h1>{{ scopeTitle }}</h1>
        <p>{{ scopeDescription }}</p>
      </div>
      <div class="designer-actions">
        <span v-if="hasUnsavedChanges" class="dirty-badge">有未保存修改</span>
        <el-button :disabled="!projectId" :loading="previewing" @click="handlePreview">预览页面</el-button>
        <el-button type="primary" :disabled="!projectId" :loading="saving" @click="saveAllDesigns">保存设计</el-button>
        <el-button @click="handleBack">返回工作台</el-button>
      </div>
    </header>

    <section class="designer-toolbar">
      <el-segmented v-model="scopeProxy" :options="scopeOptions" />
      <div class="toolbar-meta">
        <span>{{ pageDesigns.length }} 个页面</span>
        <span>{{ database.tables.length }} 张数据表</span>
      </div>
    </section>

    <el-alert
      v-if="errorMessage"
      class="designer-alert"
      type="warning"
      :title="errorMessage"
      show-icon
      :closable="false"
    />

    <div class="designer-card">
      <FrontendPageDesigner
        ref="designerRef"
        :designs="pageDesigns"
        :database="database"
        :block-definitions="businessBlockDefinitions"
        :mode="scope"
        :show-header="false"
        :saving="saving"
        :initializing="initializing"
        @update:designs="handleDesignsUpdate"
        @dirty-change="handleDirtyChange"
        @init-designs="handleInitPageDesigns"
        @create-design="handleCreatePageDesign"
        @delete-design="handleDeletePageDesign"
        @save-design="handleSavePageDesign"
      />
    </div>
  </section>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { onBeforeRouteLeave, onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import FrontendPageDesigner from '@/components/FrontendPageDesigner.vue'
import {
  createPageDesign,
  deletePageDesign,
  generateProject,
  getDatabase,
  getProject,
  initPageDesigns,
  listBusinessBlocks,
  listPageDesigns,
  savePageDesign
} from '@/api/project'

const route = useRoute()
const router = useRouter()

const designerRef = ref(null)
const loading = ref(false)
const saving = ref(false)
const initializing = ref(false)
const previewing = ref(false)
const errorMessage = ref('')
const projectName = ref('')
const database = ref({ tables: [], sql: '', erDiagram: emptyErDiagram(), businessActions: [] })
const pageDesigns = ref([])
const businessBlockDefinitions = ref([])
const hasUnsavedChanges = ref(false)

const projectId = computed(() => normalizeProjectId(route.params.projectId || route.query.projectId))
const scope = computed(() => route.query.scope === 'admin' ? 'admin' : 'frontend')
const scopeProxy = computed({
  get: () => scope.value,
  set: (value) => {
    router.replace({
      path: `/project/${projectId.value}/page-designer`,
      query: { ...route.query, scope: value }
    })
  }
})

const scopeOptions = [
  { label: '前台', value: 'frontend' },
  { label: '后台', value: 'admin' }
]

const scopeTitle = computed(() => scope.value === 'admin' ? '后台页面设计' : '前台页面设计')
const scopeDescription = computed(() => scope.value === 'admin'
  ? '配置后台管理页的查询区、工具栏、表格列、表单字段、批量操作和行按钮。'
  : '配置前台页面的字段、查询区、卡片列表、按钮和公告、轮播等业务块。')

function emptyErDiagram() {
  return {
    positions: {},
    relations: [],
    deletedEdgeIds: []
  }
}

function normalizeProjectId(value) {
  const id = Number(value)
  return Number.isFinite(id) && id > 0 ? id : null
}

function normalizeErDiagram(value) {
  const source = value && typeof value === 'object' ? value : {}
  return {
    positions: source.positions && typeof source.positions === 'object' ? source.positions : {},
    relations: Array.isArray(source.relations) ? source.relations : [],
    deletedEdgeIds: Array.isArray(source.deletedEdgeIds) ? source.deletedEdgeIds : []
  }
}

function normalizeDatabase(payload) {
  const data = payload?.data || payload || {}
  return {
    tables: Array.isArray(data.tables) ? data.tables : [],
    sql: data.sql || '',
    erDiagram: normalizeErDiagram(data.erDiagram),
    businessActions: Array.isArray(data.businessActions) ? data.businessActions : []
  }
}

async function loadDesignerData() {
  if (!projectId.value) {
    errorMessage.value = '缺少项目 ID，请从工作台重新进入页面设计器'
    return
  }
  loading.value = true
  errorMessage.value = ''
  try {
    const [projectResult, databaseResult, designResult, blockResult] = await Promise.all([
      getProject(projectId.value),
      getDatabase(projectId.value),
      listPageDesigns(projectId.value, scope.value),
      listBusinessBlocks(projectId.value, scope.value)
    ])
    projectName.value = projectResult?.projectName || ''
    database.value = normalizeDatabase(databaseResult)
    pageDesigns.value = Array.isArray(designResult) ? designResult : []
    businessBlockDefinitions.value = Array.isArray(blockResult) ? blockResult : []
    hasUnsavedChanges.value = false
  } catch (error) {
    errorMessage.value = error.message || '加载页面设计器失败'
  } finally {
    loading.value = false
  }
}

function handleDesignsUpdate(designs) {
  pageDesigns.value = Array.isArray(designs) ? designs : []
  hasUnsavedChanges.value = true
}

function handleDirtyChange(isDirty) {
  if (isDirty) {
    hasUnsavedChanges.value = true
  }
}

async function handleInitPageDesigns() {
  if (!projectId.value) return
  initializing.value = true
  errorMessage.value = ''
  try {
    const result = await initPageDesigns(projectId.value, scope.value)
    pageDesigns.value = Array.isArray(result?.designs) ? result.designs : []
    if (!pageDesigns.value.length) {
      const refreshed = await listPageDesigns(projectId.value, scope.value)
      pageDesigns.value = Array.isArray(refreshed) ? refreshed : []
    }
    hasUnsavedChanges.value = false
    ElMessage.success(`${scopeTitle.value}已初始化`)
  } catch (error) {
    errorMessage.value = error.message || `初始化${scopeTitle.value}失败`
  } finally {
    initializing.value = false
  }
}

async function handleCreatePageDesign(design) {
  if (!projectId.value) return
  const wasDirty = hasUnsavedChanges.value
  saving.value = true
  errorMessage.value = ''
  try {
    const saved = await createPageDesign(projectId.value, design, scope.value)
    pageDesigns.value = pageDesigns.value.concat(saved)
    hasUnsavedChanges.value = wasDirty
    ElMessage.success('页面已新增')
  } catch (error) {
    errorMessage.value = error.message || '新增页面失败'
  } finally {
    saving.value = false
  }
}

async function handleSavePageDesign(design) {
  if (!projectId.value || !design?.designId) return
  saving.value = true
  errorMessage.value = ''
  try {
    const saved = await savePageDesign(projectId.value, design.designId, design, scope.value)
    replacePageDesign(saved)
    hasUnsavedChanges.value = false
    ElMessage.success('页面设计已保存')
  } catch (error) {
    errorMessage.value = error.message || '保存页面设计失败'
  } finally {
    saving.value = false
  }
}

async function handleDeletePageDesign(design) {
  if (!projectId.value || !design?.designId) return
  const confirmed = await confirmDeletePage(design)
  if (!confirmed) return
  const wasDirty = hasUnsavedChanges.value
  saving.value = true
  errorMessage.value = ''
  try {
    await deletePageDesign(projectId.value, design.designId, scope.value)
    removePageDesign(design)
    hasUnsavedChanges.value = wasDirty
    ElMessage.success('页面已删除')
  } catch (error) {
    if (shouldRemoveMissingPage(error)) {
      removePageDesign(design)
      ElMessage.warning('页面已不存在，已从列表移除')
      return
    }
    errorMessage.value = error.message || '删除页面失败'
  } finally {
    saving.value = false
  }
}

function replacePageDesign(saved) {
  pageDesigns.value = pageDesigns.value.map((item) => {
    const sameDesign = String(item.designId || item.pageCode) === String(saved.designId || saved.pageCode)
    return sameDesign ? saved : item
  })
}

function removePageDesign(deleted) {
  pageDesigns.value = pageDesigns.value.filter((item) => {
    return String(item.designId || item.pageCode) !== String(deleted.designId || deleted.pageCode)
  })
}

function shouldRemoveMissingPage(error) {
  const message = String(error?.message || '')
  return message.includes('不存在') || message.includes('无权限') || message.includes('404')
}

async function confirmDeletePage(design) {
  try {
    await ElMessageBox.confirm(`确认删除页面“${design.pageName || design.pageCode}”？`, '删除页面', {
      type: 'warning',
      confirmButtonText: '删除',
      cancelButtonText: '取消'
    })
    return true
  } catch (error) {
    return false
  }
}

async function saveAllDesigns() {
  if (!projectId.value) return
  designerRef.value?.commitCurrentDraft?.()
  const pendingDesigns = pageDesigns.value.filter((design) => design?.designId)
  if (!pendingDesigns.length) {
    hasUnsavedChanges.value = false
    return
  }
  saving.value = true
  errorMessage.value = ''
  try {
    for (const design of pendingDesigns) {
      const saved = await savePageDesign(projectId.value, design.designId, design, scope.value)
      replacePageDesign(saved)
    }
    hasUnsavedChanges.value = false
    ElMessage.success('页面设计已保存')
  } catch (error) {
    errorMessage.value = error.message || '保存页面设计失败'
    throw error
  } finally {
    saving.value = false
  }
}

async function handlePreview() {
  if (!projectId.value) return
  previewing.value = true
  try {
    await saveAllDesigns()
    await generateProject(projectId.value)
    router.push(`/project/${projectId.value}/preview`)
  } catch (error) {
    errorMessage.value = error.message || '生成预览失败'
  } finally {
    previewing.value = false
  }
}

async function confirmLeaveDirty() {
  if (!hasUnsavedChanges.value) return true
  try {
    await ElMessageBox.confirm('当前页面设计有未保存修改，确认离开吗？', '未保存修改', {
      type: 'warning',
      confirmButtonText: '离开',
      cancelButtonText: '继续编辑'
    })
    return true
  } catch (error) {
    return false
  }
}

async function handleBack() {
  router.push({ path: '/generate', query: { projectId: projectId.value } })
}

watch(
  () => [projectId.value, scope.value],
  () => {
    loadDesignerData()
  }
)

onMounted(loadDesignerData)

onBeforeRouteLeave(async () => {
  return confirmLeaveDirty()
})

onBeforeRouteUpdate(async () => {
  return confirmLeaveDirty()
})
</script>

<style scoped lang="scss">
.designer-shell-page {
  display: grid;
  gap: 14px;
  min-height: calc(100vh - 76px);
  padding: 20px;
  background: #f4f7fb;
}

.designer-topbar,
.designer-toolbar,
.designer-card {
  border: 1px solid #dfe6f0;
  border-radius: 8px;
  background: #fff;
}

.designer-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 16px 18px;
}

.designer-title {
  display: grid;
  gap: 4px;
}

.breadcrumb {
  color: #667085;
  font-size: 13px;
}

.designer-title h1 {
  margin: 0;
  color: #172033;
  font-size: 22px;
}

.designer-title p {
  margin: 0;
  color: #667085;
  line-height: 1.45;
}

.designer-actions,
.designer-toolbar,
.toolbar-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.designer-actions {
  justify-content: flex-end;
}

.designer-toolbar {
  justify-content: space-between;
  padding: 10px 14px;
}

.toolbar-meta {
  color: #667085;
  font-size: 13px;
}

.dirty-badge {
  padding: 5px 9px;
  border-radius: 999px;
  background: #fff8e6;
  color: #b7791f;
  font-size: 12px;
  font-weight: 700;
}

.designer-alert {
  border-radius: 8px;
}

.designer-card {
  min-height: 0;
  overflow: visible;
}

.designer-card :deep(.page-designer-body) {
  padding: 16px;
}

@media (max-width: 860px) {
  .designer-topbar,
  .designer-toolbar {
    align-items: stretch;
    flex-direction: column;
  }

  .designer-actions {
    justify-content: flex-start;
  }
}
</style>
