/* eslint-disable no-case-declarations */
import { Transformer } from "markmap-lib";
import { IMarkmapOptions, INode, IPureNode, walkTree } from "markmap-common";
import { Markmap } from "markmap-view";

import * as domUtils from "./utils/dom.utils";
import * as promiseUtils from "./utils/promise.util";

export interface iXmindOptions {
  data?: string; // 节点数据(markdown 格式)
  dataType?: "json" | "markdown"; // 传入的数据类型
  initialExpandLevel?: number; // 初始化展开层级(默认全部展开)
  spacingVertical?: number; // 导图节点 上下间距
  scrollForPan?: boolean; // 是否支持滚动缩放
  maxWidth?: number; // 文本最大宽度
  colorList?: string[]; // 颜色列表数据
  markmapOpts?: IMarkmapOptions; // 直接传入 MarkMap 的属性
  isAnimation: boolean; // 初始化开启动画，后续是否开启动画
  style: (id: string) => string; // 自定义样式
}

// 脑图组件
class TWXmind {
  private readonly wrapper: HTMLElement; // 挂载容器元素
  private xmindSvg!: SVGElement; // SVG 渲染元素
  private resizeObserver!: ResizeObserver; // 大小变化监听器
  private readonly twXmindOptions: iXmindOptions; // 初始化参数

  // markmap
  private markmapOptions!: Partial<IMarkmapOptions>; // 初始化 markmap 参数
  private transformer!: Transformer;
  private markmap!: Markmap;

  constructor(options: { wrapper: HTMLElement; xmindOptions: iXmindOptions }) {
    const { wrapper, xmindOptions } = options;

    if (!wrapper) {
      throw new Error("TWXmind: wrapper is required");
    }

    this.wrapper = wrapper;
    this.twXmindOptions = xmindOptions;

    this.initXmindSVG(); // 元素初始化
    this.initXmind(); // 脑图初始化
  }

  // 更新脑图数据
  updateData(data: string) {
    // 更新数据
    const { root } = this.transformer.transform(data);
    // 脑图数据、位置重置
    this.markmap.setData(root);
    // 渲染完成后重置位置(渲染动画完成)
    const { duration = 50 } = this.markmapOptions;
    setTimeout(() => {
      this.markmap.fit();
    }, duration);
  }
  // 更新 JSON 数据
  updateJSONData(data: any, type: boolean) {
    const jsonObjectData = !type ? (JSON.parse(data) as IPureNode) : data;
    this.markmap.setData(jsonObjectData);
    // 渲染完成后重置位置(渲染动画完成)
    const { duration = 50 } = this.markmapOptions;
    setTimeout(() => {
      this.markmap.fit();
    }, duration);
  }
  // 更新缩放大小
  updateZoom(zoom: number) {
    this.markmap.rescale(zoom);
  }
  // 重置脑图位置
  resetSize() {
    this.markmap.fit();
  }
  // 展开所有节点
  expendAllNodes(noFit = false) {
    // 所有节点数据展开
    const mmData = this.markmap.state.data!;
    walkTree(mmData, (item, next) => {
      item.payload = {
        ...item.payload,
        fold: 0,
      };
      next();
    });
    this.markmap.renderData();
    !noFit && this.markmap.fit();
  }
  // 收起节点
  collapseNodes(noFit = false, isInitLevel = true) {
    const { initialExpandLevel } = this.twXmindOptions;
    // 收起节点层次
    const collapseDepth = isInitLevel && initialExpandLevel ? initialExpandLevel : 0;
    // 计算收起所有节点
    const mmData = this.markmap.state.data!;
    walkTree(mmData, (item, next) => {
      // 大于指定层级才需要收起
      if (item.state.depth >= collapseDepth) {
        item.payload = {
          ...item.payload,
          fold: 1,
        };
      }
      next();
    });
    // 重新渲染
    this.markmap.renderData();
    !noFit && this.markmap.fit();
  }
  // 销毁实例
  destroy() {
    this.resizeObserver.disconnect();
    this.markmap.destroy();
  }

  // 导出图片
  // public async exportDataUrl(imgSize: { width: number; height: number; } = {
  //   width: 1000,
  //   height: 1000,
  // }) {
  //   return domUtils.svgToPng(this.xmindSvg);
  // }
  // 未挂载直接导出
  static async staticExportDataUrl(opts: {
    imgSize?: { width: number; height: number };
    xmindOptions: Required<iXmindOptions>;
  }) {
    if (!opts.xmindOptions.data || !opts.xmindOptions.dataType) {
      throw new Error("TWXmind: data and dataType is required");
    }
    // 渲染元素
    const { width = 500, height = 500 } = opts.imgSize || {};
    const renderWrapper = domUtils.createHiddenWrapper("div", document.body);
    const renderSVG = domUtils.createSvgElement({
      width,
      height,
      style: `width: ${width}px; height: ${height}px;`,
    });
    renderWrapper.appendChild(renderSVG);

    // 初始化参数
    const { data, dataType, colorList, markmapOpts = {}, ...markmapOptions } = opts.xmindOptions;
    const initOptions: Partial<IMarkmapOptions> = {
      ...markmapOpts, // 直传属性
      ...markmapOptions, // 代理属性
      duration: 0, // 立即渲染，不需要动画
    };
    if (colorList && colorList.length) {
      initOptions.color = this.getMindNodeColorForPath(colorList); // 获取颜色计算方法
    }

    // 渲染脑图
    const exportMarkmap = Markmap.create(renderSVG, initOptions);
    switch (dataType) {
      case "json":
        const isObj = typeof data === "object";
        const jsonObjectData = isObj ? data : (JSON.parse(data) as IPureNode);
        exportMarkmap.setData(jsonObjectData);
        break;
      case "markdown":
        const transformer = new Transformer(); // 初始化数据装换器
        const { root } = transformer.transform(data);
        // 脑图数据、位置重置
        exportMarkmap.setData(root);
        break;
      default:
    }
    // 渲染完成后重置位置
    await promiseUtils.delay(0); // dom 结构变更完成
    exportMarkmap.fit();
    await promiseUtils.delay(0); // dom 结构变更完成

    // 1s 后清理
    // setTimeout(() => {
    //   exportMarkmap.destroy();
    //   document.body.removeChild(renderWrapper);
    // }, 1000);

    // 然后导出图片
    return domUtils.svgToPng(renderSVG);
  }

  // 初始化 SVG 元素
  private initXmindSVG() {
    // 创建，并挂载 SVG 元素
    this.xmindSvg = domUtils.createSvgElement();
    this.wrapper.appendChild(this.xmindSvg);
    // 初始化 SVG 大小
    domUtils.updateElementSizeWithWrapper(this.xmindSvg, this.wrapper);
    // 监听容器大小变化，更新 SVG 大小
    this.resizeObserver = new ResizeObserver(() => {
      // 更新画板大小
      domUtils.updateElementSizeWithWrapper(this.xmindSvg, this.wrapper);
      // 脑图位置重置
      // this.twXmindOptions.isAnimation && this.markmap.fit();
    });
    this.resizeObserver.observe(this.wrapper);
  }

  // 初始化脑图组件
  private initXmind() {
    this.transformer = new Transformer(); // 初始化数据装换器
    // 脑图初始化
    const { data, dataType, colorList, markmapOpts = {}, ...markmapOptions } = this.twXmindOptions;
    // 初始化参数
    const initOptions: Partial<IMarkmapOptions> = {
      ...markmapOpts, // 直传属性
      ...markmapOptions, // 代理属性
    };
    if (colorList && colorList.length) {
      initOptions.color = TWXmind.getMindNodeColorForPath(colorList); // 获取颜色计算方法
    }

    this.markmapOptions = initOptions; // 保存初始化参数
    this.markmap = Markmap.create(this.xmindSvg, initOptions);
    if (data) {
      if (!dataType) {
        throw new Error("dataType is required with data");
      }
      switch (dataType) {
        case "json":
          const isObj = typeof data === "object";
          this.updateJSONData(data, isObj);
          break;
        case "markdown":
          this.updateData(data);
          break;
        default:
      }
    }
  }

  // 返回节点颜色计算方法
  static readonly getMindNodeColorForPath = (colorList: string[]) => {
    const colorLength = colorList.length;
    let lastColorIndex = 0; // 下一次使用的颜色
    const pathColorMap: Record<string, string> = {
      1: colorList[0], // 跟节点使用固定颜色
      "1.": colorList[0], // 跟节点使用固定颜色
    };

    // 返回颜色计算方法
    return (node: INode) => {
      const {
        state: { path },
      } = node;
      const secondPath = path.split(".").splice(0, 2).join(".");
      // 已存在颜色配置，直接返回
      if (pathColorMap[secondPath]) {
        return pathColorMap[secondPath];
      }

      // 计算颜色
      if (lastColorIndex < colorLength) {
        pathColorMap[secondPath] = colorList[lastColorIndex];
        lastColorIndex = (lastColorIndex + 1) % colorLength;
      }
      return pathColorMap[secondPath];
    };
  };
}

export { TWXmind };
