<!--
  PhonePreview.vue — 中间预览区

  功能：
  - 手机/平板/PC 多端模拟
  - SortableJS 拖拽排序
  - 从组件库拖入（onAdd）
  - 点击选中组件
  - 10种组件实时渲染预览
  - 拖拽手柄
-->
<template>
  <main class="canvas-panel">
    <!-- 多端切换 -->
    <div class="device-toolbar">
      <div class="device-switcher">
        <el-radio-group v-model="store.previewDevice" size="small">
          <el-radio-button value="mobile">📱 手机</el-radio-button>
          <el-radio-button value="tablet">📟 平板</el-radio-button>
          <el-radio-button value="desktop">🖥️ 电脑</el-radio-button>
        </el-radio-group>
      </div>
      <div class="canvas-info">
        {{ store.componentCount }} 个组件 · {{ store.previewWidth }}px
        <span v-if="store.canUndo" class="undo-hint">· <kbd>Ctrl+Z</kbd> 撤销</span>
      </div>
    </div>

    <div class="canvas-scroll">
      <div
        class="device-frame"
        :class="'frame-' + store.previewDevice"
        :style="{ maxWidth: store.previewWidth + 'px' }"
      >
        <!-- 状态栏 -->
        <div class="frame-statusbar">
          <span class="fs-time">9:41</span>
          <div class="fs-icons">
            <span v-if="store.previewDevice !== 'desktop'">📶</span>
            <span>🔋</span>
          </div>
        </div>

        <!-- 预览屏 - SortableJS 容器 + 接收组件库拖拽 -->
        <div
          ref="previewRef"
          class="frame-screen"
          :class="{ 'is-empty': store.components.length === 0, 'is-drag-over': isDragOver }"
          @click="store.clearSelection()"
          @dragover.prevent="onDragOver($event)"
          @dragleave="onDragLeave"
          @drop.prevent="onDrop($event)"
        >
          <div v-if="store.components.length === 0" class="empty-hint">
            <div class="empty-icon">📱</div>
            <p>点击左侧组件添加</p>
            <p class="empty-sub">或拖拽组件到此处</p>
          </div>

          <div
            v-for="(comp, index) in store.components"
            :key="comp.id"
            class="preview-item"
            :class="{ selected: store.selectedId === comp.id, hovering: hoverId === comp.id && store.selectedId !== comp.id, dragging: draggingId === comp.id }"
            @click.stop="store.selectComponent(comp.id)"
            @mouseenter="hoverId = comp.id"
            @mouseleave="hoverId = null"
          >
            <!-- 悬停/选中时显示操作栏 -->
            <div v-if="store.selectedId === comp.id || hoverId === comp.id" class="item-toolbar">
              <el-button-group size="small">
                <el-button size="small" @click.stop="moveUp(index)" :disabled="index === 0" title="上移">↑</el-button>
                <el-button size="small" @click.stop="moveDown(index)" :disabled="index === store.components.length - 1" title="下移">↓</el-button>
                <el-button size="small" @click.stop="handleCopy(comp.id)" title="复制">📋</el-button>
                <el-button size="small" type="danger" @click.stop="handleRemove(comp.id)" title="删除">✕</el-button>
              </el-button-group>
            </div>

            <!-- 拖拽手柄（选中或悬停时可见） -->
            <div class="drag-handle" :class="{ visible: store.selectedId === comp.id || hoverId === comp.id }" title="拖拽排序">
              <span>⠿</span>
            </div>

            <!-- 组件预览渲染 -->
            <div class="component-preview">
              <SwiperPreview    v-if="comp.type === 'swiper'"        :props="comp.props" />
              <NavGroupPreview  v-else-if="comp.type === 'navGroup'"       :props="comp.props" />
              <TitleBarPreview  v-else-if="comp.type === 'titleBar'"       :props="comp.props" />
              <ImageAdPreview   v-else-if="comp.type === 'imageAd'"        :props="comp.props" />
              <NoticeBarPreview v-else-if="comp.type === 'noticeBar'"      :props="comp.props" />
              <SpacerPreview    v-else-if="comp.type === 'spacer'"         :props="comp.props" />
              <DividerPreview   v-else-if="comp.type === 'divider'"        :props="comp.props" />
              <ProductListPreview   v-else-if="comp.type === 'productList'"    :props="comp.props" />
              <SeckillPreview   v-else-if="comp.type === 'seckillEntry'"   :props="comp.props" />
              <CouponPreview    v-else-if="comp.type === 'couponEntry'"    :props="comp.props" />
              <GrouponPreview   v-else-if="comp.type === 'grouponEntry'"   :props="comp.props" />
              <PromotionListPreview v-else-if="comp.type === 'promotionList'":props="comp.props" />
              <SearchBoxPreview v-else-if="comp.type === 'searchBox'"     :props="comp.props" />
              <QuickEntryPreview v-else-if="comp.type === 'quickEntry'"    :props="comp.props" />
              <ArticleListPreview v-else-if="comp.type === 'articleList'"  :props="comp.props" />
              <VideoPreview     v-else-if="comp.type === 'videoModule'"    :props="comp.props" />
              <WaterfallPreview       v-else-if="comp.type === 'waterfall'"        :props="comp.props" />
              <CouponWallPreview      v-else-if="comp.type === 'couponWall'"       :props="comp.props" />
              <NoticeScrollPreview    v-else-if="comp.type === 'noticeScroll'"      :props="comp.props" />
              <CountdownBannerPreview v-else-if="comp.type === 'countdownBanner'"   :props="comp.props" />
              <CategoryGridPreview    v-else-if="comp.type === 'categoryGrid'"      :props="comp.props" />
              <div v-else class="unknown-comp">
                <span>{{ comp.type }}</span> — 未知组件
              </div>
            </div>
          </div>
        </div>

        <!-- 底部指示器 -->
        <div class="frame-home-bar"></div>
      </div>
    </div>
  </main>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
import Sortable from 'sortablejs'
import { useDesignStore } from '../../../stores/designStore.js'
import { COMPONENT_REGISTRY } from '../utils/componentRegistry.js'

// 预览组件（内联渲染，保持轻量）
import SwiperPreview from './preview/SwiperPreview.vue'
import NavGroupPreview from './preview/NavGroupPreview.vue'
import TitleBarPreview from './preview/TitleBarPreview.vue'
import ImageAdPreview from './preview/ImageAdPreview.vue'
import NoticeBarPreview from './preview/NoticeBarPreview.vue'
import SpacerPreview from './preview/SpacerPreview.vue'
import DividerPreview from './preview/DividerPreview.vue'
import ProductListPreview from './preview/ProductListPreview.vue'
import SeckillPreview from './preview/SeckillEntryPreview.vue'
import CouponPreview from './preview/CouponEntryPreview.vue'
import GrouponPreview from './preview/GrouponEntryPreview.vue'
import PromotionListPreview from './preview/PromotionListPreview.vue'
import SearchBoxPreview from './preview/SearchBoxPreview.vue'
import QuickEntryPreview from './preview/QuickEntryPreview.vue'
import ArticleListPreview from './preview/ArticleListPreview.vue'
import VideoPreview from './preview/VideoPreview.vue'
import WaterfallPreview from './preview/WaterfallPreview.vue'
import CouponWallPreview from './preview/CouponWallPreview.vue'
import NoticeScrollPreview from './preview/NoticeScrollPreview.vue'
import CountdownBannerPreview from './preview/CountdownBannerPreview.vue'
import CategoryGridPreview from './preview/CategoryGridPreview.vue'

const store = useDesignStore()
const previewRef = ref(null)
let sortableInstance = null
const draggingId = ref(null)
// 是否正有组件从组件库拖入（用于高亮提示）
const isDragOver = ref(false)
// 鼠标悬停的组件 id（CRMEB 式：悬停即浮现操作条）
const hoverId = ref(null)

// 从组件库拖入位置估算（基于 Y 坐标相对各子元素顶部）
function estimateDropIndex(clientY) {
  const screen = previewRef.value
  if (!screen || store.components.length === 0) return store.components.length
  let target = store.components.length
  let best = Infinity
  screen.querySelectorAll('.preview-item').forEach((el) => {
    const r = el.getBoundingClientRect()
    if (clientY >= r.bottom) return // 在该元素下方，继续
    const dist = clientY - r.top
    if (dist >= 0 && dist < best) {
      best = dist
      // 取该元素 index
      const idx = Array.prototype.indexOf.call(screen.children, el)
      target = idx
    }
  })
  return target
}

function onDragOver(e) {
  isDragOver.value = true
  e.dataTransfer && (e.dataTransfer.dropEffect = 'copy')
}

function onDragLeave() {
  isDragOver.value = false
}

function onDrop(e) {
  isDragOver.value = false
  let type = null
  if (e.dataTransfer) {
    type = e.dataTransfer.getData('application/x-litedesign-component') || e.dataTransfer.getData('text/plain')
  }
  // fallback：由 SortableJS 外部插入时 dataset 提供
  if (!type) type = e.target?.dataset?.type
  if (!type || !COMPONENT_REGISTRY[type]) return
  const idx = estimateDropIndex(e.clientY)
  store.addComponent(type, idx)
}

const emit = defineEmits(['add-component'])

// 上下移
function moveUp(index) {
  if (index <= 0) return
  store.moveComponent(index, index - 1)
}

function moveDown(index) {
  if (index >= store.components.length - 1) return
  store.moveComponent(index, index + 1)
}

function handleRemove(id) {
  store.removeComponent(id)
}

function handleCopy(id) {
  const comp = store.components.find(c => c.id === id)
  if (!comp) return
  store.addComponent(comp.type, store.components.findIndex(c => c.id === id) + 1)
}

// 初始化 SortableJS
function initSortable() {
  if (!previewRef.value) return

  sortableInstance = new Sortable(previewRef.value, {
    group: {
      name: 'lite-design',
      pull: true,
      // 关闭 Sortable 的跨组外部接收，外部(组件库)拖入改由原生 drop 处理(onDrop)，避免重复插入
      put: false
    },
    animation: 200,
    easing: 'cubic-bezier(.2,.8,.4,1)',
    handle: '.drag-handle',
    ghostClass: 'sortable-ghost',
    dragClass: 'sortable-drag',
    delay: 150,
    delayOnTouchOnly: true,
    onStart: (evt) => {
      draggingId.value = store.components[evt.oldIndex]?.id || null
    },
    onEnd: (evt) => {
      draggingId.value = null
      if (evt.oldIndex !== undefined && evt.newIndex !== undefined) {
        store.moveComponent(evt.oldIndex, evt.newIndex)
      }
    },
    onAdd: (evt) => {
      // 从外部拖入 — 由 WidgetPanel 的 dragstart 提供 type
      const type = evt.item.dataset.type
      if (type && COMPONENT_REGISTRY[type]) {
        // 移除 Sortable 自动插入的占位
        if (evt.item.parentNode) evt.item.parentNode.removeChild(evt.item)
        store.addComponent(type, evt.newIndex)
      }
    }
  })
}

// 组件列表变化后重新初始化 Sortable（Vue 重渲染后 DOM 会变）
watch(() => store.components.length, async () => {
  await nextTick()
  if (sortableInstance) sortableInstance.destroy()
  initSortable()
})

watch(() => store.previewDevice, async () => {
  await nextTick()
  if (sortableInstance) sortableInstance.destroy()
  initSortable()
})

onMounted(() => {
  initSortable()
})

onBeforeUnmount(() => {
  if (sortableInstance) sortableInstance.destroy()
})

// 暴露添加组件方法给父级
defineExpose({ addComponent: (type, index) => store.addComponent(type, index) })
</script>

<style scoped>
.canvas-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #f0f2f5;
  overflow: hidden;
}

.device-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  background: #fff;
  border-bottom: 1px solid #e8eaed;
  flex-shrink: 0;
}

.canvas-info {
  font-size: 12px;
  color: #999;
}

.undo-hint kbd {
  background: #f0f0f0;
  border: 1px solid #ddd;
  border-radius: 3px;
  padding: 0 4px;
  font-size: 11px;
}

.canvas-scroll {
  flex: 1;
  overflow-y: auto;
  display: flex;
  justify-content: center;
  padding: 24px 16px;
}

/* 设备外框 */
.device-frame {
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 4px 20px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.03);
  overflow: hidden;
  transition: max-width .3s, border-radius .3s;
  width: 100%;
}

.frame-desktop {
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0,0,0,.06);
}

.frame-tablet {
  border-radius: 16px;
}

.frame-statusbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px 6px;
  font-size: 12px;
  color: #333;
  background: #fff;
}

.fs-icons {
  display: flex;
  gap: 4px;
  font-size: 10px;
}

.frame-screen {
  min-height: 400px;
  padding: 4px 0;
  background: #f8f8f8;
}

.frame-screen.is-empty {
  min-height: 500px;
}

/* 从组件库拖入时的高亮提示 */
.frame-screen.is-drag-over {
  background: #eef2ff;
  box-shadow: inset 0 0 0 2px #7C3AED;
  min-height: 500px;
}

/* 预览项 */
.preview-item {
  position: relative;
  margin: 3px 8px;
  border: 2px solid transparent;
  border-radius: 10px;
  transition: border-color .15s, box-shadow .15s;
  cursor: pointer;
}

.preview-item:hover,
.preview-item.hovering {
  border-color: #7C3AED;
  box-shadow: 0 0 0 1px rgba(124,58,237,.2);
}

.preview-item.selected {
  border-color: #7C3AED;
  box-shadow: 0 0 0 1px rgba(124,58,237,.15), 0 2px 8px rgba(124,58,237,.06);
  background: rgba(124,58,237,.02);
}

.preview-item.dragging {
  opacity: 0.5;
}

/* 操作栏 */
.item-toolbar {
  position: absolute;
  top: -14px;
  right: 8px;
  z-index: 20;
  display: flex;
  gap: 2px;
}

.item-toolbar :deep(.el-button) {
  padding: 0 6px;
  height: 24px;
  font-size: 11px;
  min-width: 24px;
}

/* 拖拽手柄 */
.drag-handle {
  position: absolute;
  top: -1px;
  left: -1px;
  width: 22px;
  height: 22px;
  display: none;
  align-items: center;
  justify-content: center;
  background: #7C3AED;
  color: #fff;
  border-radius: 8px 0 8px 0;
  font-size: 12px;
  cursor: grab;
  z-index: 15;
  opacity: 0;
  transition: opacity .15s;
}

.drag-handle.visible {
  display: flex;
  opacity: 1;
}

.drag-handle:active {
  cursor: grabbing;
}

/* 组件预览容器 */
.component-preview {
  pointer-events: none; /* 预览区内禁止实际交互 */
  overflow: hidden;
}

/* 空状态 */
.empty-hint {
  text-align: center;
  padding: 100px 0 80px;
  color: #bbb;
}

.empty-icon {
  font-size: 48px;
  margin-bottom: 8px;
}

.empty-hint p {
  font-size: 14px;
  margin: 4px 0;
}

.empty-sub {
  font-size: 12px;
  opacity: .6;
}

/* 未知组件 */
.unknown-comp {
  padding: 20px;
  text-align: center;
  color: #999;
  background: #fff;
  border-radius: 8px;
  font-size: 13px;
}

.unknown-comp span {
  font-weight: 700;
  color: #e74c3c;
}

/* 底部指示条 */
.frame-home-bar {
  text-align: center;
  padding: 6px 0 10px;
  color: #ddd;
  font-size: 28px;
  line-height: 1;
}

.frame-home-bar::after {
  content: '▬';
}

/* Sortable 幽灵占位 → CRMEB 式插入指示线 */
:deep(.sortable-ghost) {
  opacity: 1 !important;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  height: 6px !important;
  margin: 2px 8px !important;
  min-height: 6px !important;
  padding: 0 !important;
  border-radius: 3px !important;
  position: relative;
  overflow: hidden;
}

:deep(.sortable-ghost::before) {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 3px;
  border-radius: 3px;
  background: #7C3AED;
  box-shadow: 0 0 6px rgba(124,58,237,.5);
}

:deep(.sortable-ghost *) {
  visibility: hidden;
}

:deep(.sortable-drag) {
  opacity: 0.85;
  transform: rotate(1.5deg) scale(1.03);
  box-shadow: 0 12px 28px rgba(0,0,0,.18);
  cursor: grabbing;
}
</style>
