// 导入 HtmlNode 及其模型，为后续继承做准备
import { HtmlNode, HtmlNodeModel } from "@logicflow/core";
// 导入 Vue 相关方法，用于渲染组件
import { createApp, h, nextTick } from "vue";
import ElementPlus from "element-plus";
// 导入 Vue 组件
import EndNode from "./endNode.vue";
import JsonViewer from 'vue3-json-viewer'

/**
 * 定义一个 元素的 HTML 节点类，继承自 HtmlNode
 * 该类负责在 HTML 中渲染 元素，并处理其交互逻辑
 */
class EndNodeHtmlNode extends HtmlNode {
  resizeObserver = null;
  isMounted; // 标记组件是否已挂载
  r; // 渲染函数
  app; // Vue 应用实例
  container = null;

  /**
   * 构造函数
   * @param props 传递给节点的属性，包括模型、图模型等
   */
  constructor(props) {
    super(props);
    this.initVueApp(props);
  }

  initVueApp(props) {
    this.isMounted = false;

    this.hideAnchor = false;
    this.autoExpand = true; // 防止锚点被折叠
    this.anchorsPreset = "default"; // 重置锚点预设
    // 创建 元素的渲染函数
    this.r = h(EndNode, {
      model: props.model,
      graphModel: props.graphModel,
      properties: {
        ...props.model.getProperties(),
      },
      text: props.model.text.value,
      onContentChange: this.handleContentChange.bind(this),
      onBindRef: this.handleComponentInstance.bind(this),
    });

    // 创建 Vue 应用实例，并指定渲染函数
    this.app = createApp({
      render: () => this.r,
    });
  }

  /**
   * 将 HTML 内容设置到指定的根元素上
   * @param rootEl 根元素
   */
  async setHtml(rootEl) {
    if (!this.isMounted) {
      this.isMounted = true;
      this.container = document.createElement("div");
      this.container.style.display = "inline-block"; // 关键：确保容器自适应内容

      rootEl.appendChild(this.container);
      this.app.use(ElementPlus); // 关键：单独注册ElementPlus
      this.app.use(JsonViewer)
      this.app.mount(this.container);
      await nextTick();
      this.setupSizeObserver();
    } else {
      this.r.component.props.properties = this.props.model.getProperties();
    }
  }

  /**
   * 获取节点文本内容
   * 对于元素，返回 null，因为其内容由特定组件渲染
   * @returns {null}
   */
  getText() {
    return null;
  }

  handleComponentInstance(data) {
    // 将组件实例保存到节点模型
    this.props.model.setComponentInstance(data);
  }

  handleContentChange() {
    // 内容变化时强制更新尺寸
    this.updateNodeSize();
  }

  // 渲染完成后获取实际尺寸
  updateNodeSize() {
    if (this.container) {
      const { SCALE_X, SCALE_Y } = this.props.graphModel.transformModel;
      const node = this.container.querySelector(".node__container");
      const rect = node.getBoundingClientRect();
      this.props.model.updateSize(rect.width / SCALE_X, rect.height / SCALE_Y);
    }
  }

  setupSizeObserver() {
    // 首次渲染立即检测
    requestAnimationFrame(() => {
      this.updateNodeSize();
      // 持续监听变化
      this.resizeObserver = new ResizeObserver(() => {
        this.updateNodeSize();
      });
      this.resizeObserver.observe(this.container);
    });
  }

  // 组件卸载时移除监听
  onDestroy() {
    this.resizeObserver?.disconnect();
  }
}

/**
 * 定义一个元素的 HTML 模型类，继承自 HtmlNodeModel
 * 该类主要设置节点的属性和样式
 */
class EndNodeHtmlModel extends HtmlNodeModel {
  initNodeData(data) {
    super.initNodeData(data);
  }

  // 保存组件实例引用
  setComponentInstance(instance) {
    this.componentInstance = instance;
  }

  // 验证表单
  async validateForm() {
    return { valid: true, message: "无验证方法" };
  }

  /**
   * 设置节点属性
   * 包括宽度、高度、文本编辑属性等
   */
  setAttributes() {
    // 初始设置为0，后续动态更新
    this.width = 0;
    this.height = 0;
    this.text.editable = false;
  }

  updateSize(width, height) {
    this.width = width + 24;
    this.height = height + 50;
    this.initNodeData(this); // 触发节点重绘
  }

  // 定义节点只有左右两个锚点. 锚点位置通过中心点和宽度算出来。
  getDefaultAnchor() {
    let _a = this,
      x = _a.x,
      y = _a.y,
      width = _a.width,
      height = _a.height;
    return [
      {
        x: x - width / 2,
        y: y - 25,
        name: "left",
        id: "".concat(this.id, "_3"),
        properties: { connectionType: "target" },
      },
    ];
  }

  /**
   * 获取节点轮廓样式
   * 覆盖父类方法，设置 stroke 属性为 none，以适应特定的视觉效果
   * @returns {object} 节点轮廓样式
   */
  getOutlineStyle() {
    const style = super.getOutlineStyle();
    style.stroke = "none";
    style.hover.stroke = "none";
    return style;
  }
}

// 导出方法注册
export function registerEndNode(lf) {
  lf.register({
    type: "end",
    view: EndNodeHtmlNode,
    model: EndNodeHtmlModel,
  });
}
