<script setup lang="ts">
import type { BlockInstance, BlockSchema } from './types';

import { computed } from 'vue';

import MIcon from '#/components/icon/icon.vue';

/**
 * 中间画布：按 targetArrayPath 分组渲染块实例
 * 每个分组是一个 SortableJS 接收区，可拖入、排序、删除
 */
const props = defineProps<{
  /** 所有块定义（按 type 查找对应 schema） */
  blockSchemas: BlockSchema[];
  /** 所有块实例（已拖入画布的） */
  instances: BlockInstance[];
  /** 当前选中的块实例 ID（高亮显示） */
  selectedInstanceId?: string;
}>();

const emit = defineEmits<{
  /** 选中块实例（点击时触发） */
  select: [instanceId: string];
  /** 删除块实例 */
  remove: [instanceId: string];
}>();

/**
 * 按 targetArrayPath 分组的渲染结构
 * 每个分组对应一个 SortableJS 接收区
 */
const groupedRender = computed(() => {
  // 收集所有出现的 targetArrayPath，按 blockSchemas 顺序排序
  const orderedPaths: string[] = [];
  const labelMap: Record<string, { label: string; maxCount?: number }> = {};
  for (const schema of props.blockSchemas) {
    if (!orderedPaths.includes(schema.targetArrayPath)) {
      orderedPaths.push(schema.targetArrayPath);
      labelMap[schema.targetArrayPath] = {
        label: schema.targetArrayPath,
        maxCount: schema.maxCount,
      };
    }
  }

  // 把 instances 按目标路径分组
  const grouped: Record<string, BlockInstance[]> = {};
  for (const inst of props.instances) {
    const schema = props.blockSchemas.find((s) => s.type === inst.type);
    if (!schema) continue;
    const path = schema.targetArrayPath;
    if (!grouped[path]) grouped[path] = [];
    grouped[path].push(inst);
  }

  return orderedPaths.map((path) => ({
    path,
    label: labelMap[path]?.label ?? path,
    maxCount: labelMap[path]?.maxCount,
    items: grouped[path] ?? [],
  }));
});

/**
 * 获取块实例的 schema 定义
 */
function getSchema(type: string): BlockSchema | undefined {
  return props.blockSchemas.find((s) => s.type === type);
}

/**
 * 获取块实例的简要描述（属性面板编辑的字段值预览）
 */
function getInstanceSummary(inst: BlockInstance): string {
  const schema = getSchema(inst.type);
  if (!schema) return '';
  const firstField = schema.fields[0];
  if (!firstField) return '';
  // 嵌套路径取最末级
  const path = firstField.name.split('.');
  let value: any = inst.data;
  for (const key of path) {
    value = value?.[key];
  }
  return value ? String(value) : '（未填写）';
}

function handleClick(instanceId: string) {
  emit('select', instanceId);
}

function handleRemove(instanceId: string) {
  emit('remove', instanceId);
}
</script>

<template>
  <div class="canvas">
    <div class="panel-header">
      <span class="title">画布</span>
      <span class="hint">拖入 / 排序 / 点击编辑属性</span>
    </div>
    <div class="canvas-body">
      <div
        v-for="group in groupedRender"
        :key="group.path"
        class="canvas-group"
      >
        <div class="group-header">
          <span class="group-label">{{ group.label }}</span>
          <span class="group-count">
            {{ group.items.length }}{{ group.maxCount ? `/${group.maxCount}` : '' }}
          </span>
        </div>
        <div
          class="group-dropzone"
          :data-target-array-path="group.path"
        >
          <div
            v-for="inst in group.items"
            :key="inst.id"
            class="instance-item"
            :class="{ selected: inst.id === selectedInstanceId }"
            :data-instance-id="inst.id"
            @click.stop="handleClick(inst.id)"
          >
            <div class="instance-info">
              <MIcon
                v-if="getSchema(inst.type)?.icon"
                :icon="getSchema(inst.type)!.icon"
                size="14"
              />
              <div class="instance-text">
                <div class="instance-label">{{ getSchema(inst.type)?.label }}</div>
                <div class="instance-summary">{{ getInstanceSummary(inst) }}</div>
              </div>
            </div>
            <button
              type="button"
              class="instance-remove"
              title="删除"
              @click.stop="handleRemove(inst.id)"
            >
              ×
            </button>
          </div>
          <div v-if="group.items.length === 0" class="empty-dropzone">
            拖入组件
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.canvas {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  background: var(--ant-color-bg-container, #fff);
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--ant-color-border-secondary, #e5e6eb);
  font-size: 13px;

  .title {
    font-weight: 600;
    color: var(--ant-color-text, #1d2129);
  }

  .hint {
    color: var(--ant-color-text-tertiary, #86909c);
    font-size: 11px;
  }
}

.canvas-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}

.canvas-group {
  margin-bottom: 20px;
}

.group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  font-size: 12px;

  .group-label {
    color: var(--ant-color-text-secondary, #4e5969);
    font-weight: 500;
    font-family: 'JetBrains Mono', monospace;
  }

  .group-count {
    color: var(--ant-color-text-tertiary, #86909c);
  }
}

.group-dropzone {
  min-height: 60px;
  padding: 8px;
  border: 2px dashed var(--ant-color-border, #d9d9d9);
  border-radius: 6px;
  background: var(--ant-color-fill-quaternary, #fafbfc);
}

.empty-dropzone {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  color: var(--ant-color-text-quaternary, #c9cdd4);
  font-size: 12px;
}

.instance-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  margin-bottom: 6px;
  border: 1px solid var(--ant-color-border-secondary, #e5e6eb);
  border-radius: 4px;
  background: var(--ant-color-bg-container, #fff);
  cursor: pointer;
  transition: all 0.15s;

  &:last-child {
    margin-bottom: 0;
  }

  &:hover {
    border-color: var(--ant-color-primary, #165dff);
  }

  &.selected {
    border-color: var(--ant-color-primary, #165dff);
    background: var(--ant-color-primary-bg, #f2f7ff);
    box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.15);
  }
}

.instance-info {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.instance-text {
  flex: 1;
  min-width: 0;
}

.instance-label {
  font-size: 13px;
  color: var(--ant-color-text, #1d2129);
  font-weight: 500;
}

.instance-summary {
  font-size: 11px;
  color: var(--ant-color-text-tertiary, #86909c);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.instance-remove {
  width: 18px;
  height: 18px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ant-color-text-tertiary, #86909c);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: all 0.15s;

  &:hover {
    background: var(--ant-color-error, #f53f3f);
    color: #fff;
  }
}
</style>
