/**
 * 质量组件 → GrapesJS 产物
 * <p>
 * 协议（QualityComponentDefinition）与 GrapesJS 的桥接只在这一层：
 * 组件块、画布内容、属性面板（traits）都由 definition 推导，组件实现里不出现 GrapesJS 概念。
 */
import type { BlockProperties, ComponentAdd, TraitProperties } from 'grapesjs';

import type {
  QualityComponentContent,
  QualityComponentDefinition,
  QualityFieldSchema,
  QualityProps,
} from './types';

import { QUALITY_TYPE_ATTR, propAttrName } from './attrs';
import { listQualityComponents } from './registry';
import { propsToAttributes } from './serializer';
import { BINDING_TRAIT_TYPE } from './trait-binding';
import { resolveQualityProps } from './validator';

/** 落到画布上的组件定义：协议内容 + 属性面板字段 */
export interface QualityCanvasComponent extends QualityComponentContent {
  traits?: TraitProperties[];
}

/** definition + 属性 → 画布内容，attributes 里带上类型标记与全部业务属性 */
export function buildQualityContent(
  definition: QualityComponentDefinition,
  props?: QualityProps,
): QualityCanvasComponent {
  const resolved = resolveQualityProps(definition, props);
  const content = definition.buildContent(resolved);
  return {
    ...content,
    attributes: {
      ...content.attributes,
      [QUALITY_TYPE_ATTR]: definition.type,
      ...propsToAttributes(definition, resolved),
    },
    traits: buildQualityTraits(definition),
  };
}

/**
 * 属性面板字段。
 * <p>
 * 默认 changeProp 为 false，trait 值直接写回组件的 data-qc-<key> 属性，
 * 与 serializer 的读取路径保持一致。
 */
export function buildQualityTraits(
  definition: QualityComponentDefinition,
): TraitProperties[] {
  return definition.propertySchema.map((field) => traitFromField(definition, field));
}

function traitFromField(
  definition: QualityComponentDefinition,
  field: QualityFieldSchema,
): TraitProperties {
  const base: TraitProperties = {
    name: propAttrName(field.key),
    label: field.label,
    placeholder: field.placeholder,
  };
  // 可绑定字段用自定义控件：既能手工输入，也能从数据字段里挑，挑中的写成 {{路径}}
  if (field.bindable && (field.type === 'string' || field.type === 'text')) {
    return { ...base, type: BINDING_TRAIT_TYPE };
  }
  switch (field.type) {
    case 'boolean': {
      return {
        ...base,
        type: 'checkbox',
        // 显式声明真/假字面量，DOM 属性只能是字符串，靠它才能稳定往返
        valueTrue: 'true',
        valueFalse: 'false',
        default: String(field.defaultValue ?? false),
      };
    }
    case 'enum': {
      return {
        ...base,
        type: 'select',
        options: (field.options ?? []).map((option) => ({
          id: String(option.value),
          name: option.label,
        })),
        default: field.defaultValue === undefined ? undefined : String(field.defaultValue),
      };
    }
    case 'number': {
      return {
        ...base,
        type: 'number',
        default: field.defaultValue === undefined ? undefined : String(field.defaultValue),
      };
    }
    case 'text': {
      return { ...base, type: 'textarea' };
    }
    default: {
      return { ...base, type: 'text' };
    }
  }
}

/** definition → 左侧面板的一个组件块 */
export function buildQualityBlock(definition: QualityComponentDefinition): BlockProperties {
  return {
    id: `quality-${definition.type}`,
    label: definition.label,
    category: definition.category,
    media: definition.icon,
    content: buildQualityContent(definition) as unknown as BlockProperties['content'],
    // 点击组件块追加到纸张末尾。GrapesJS 默认追加进「当前选中的组件」内部，
    // 在报告这种扁平结构里会把新组件塞进标题、表格单元格等元素，还会顶掉它们原有的文本。
    // 需要嵌套时仍可用拖拽精确落点。
    onClick: (block, editor) => {
      const content = block.get('content') as ComponentAdd;
      editor.getWrapper()?.append(content);
    },
  };
}

/** 注册表里的全部组件 → GrapesJS 组件块列表 */
export function buildQualityBlocks(): BlockProperties[] {
  return listQualityComponents().map(buildQualityBlock);
}