import { registerEdge } from '@antv/g6';

/**
 * cubic 三阶贝塞尔曲线，虚线运动
 * @key cubic-animate-line-dash
 */
export function edgeCubicAnimateLineDash() {
  registerEdge(
    'cubic-animate-line-dash',
    {
      afterDraw(cfg, group) {
        if (!group) return;
        // 获取组中的第一个形状
        const shape = group.get('children')[0];
        // 定义动画
        let index = 0;
        shape.animate(
          () => {
            index++;
            if (index > 8) {
              index = 0;
            }
            return {
              lineDash: [4, 2, 1, 2],
              lineDashOffset: -index,
            };
          },
          {
            repeat: true, // 是否重复执行动画
            duration: 3000, // 执行一次的持续时间
          }
        );
      },
    },
    'cubic' // 扩展内置边
  );
}

/**
 * cubic 三阶贝塞尔曲线，圆点沿边运动
 * @key cubic-animate-circle-move
 */
export function edgeCubicAnimateCircleMove() {
  registerEdge(
    'cubic-animate-circle-move',
    {
      afterDraw(cfg, group) {
        if (!group) return;
        // 获取组中的第一个形状
        const shape = group.get('children')[0];
        // 边缘路径的起始位置
        const startPoint = shape.getPoint(0);
        const fillColor = cfg?.labelCfg?.style?.fill || '#1890ff';
        // 添加圆圈形状
        const circle = group.addShape('circle', {
          attrs: {
            x: startPoint.x,
            y: startPoint.y,
            fill: fillColor,
            r: 3,
          },
          // 在 G6 3.3 及更高版本中必须指定。它可以是你想要的任何字符串，但在自定义项目类型中应该是唯一的
          name: 'circle-shape',
        });

        // 定义动画
        circle.animate(
          (ratio: any) => {
            // 每帧中的操作。比率范围从 0 到 1，表示动画的进度。返回修改后的配置
            // 根据比率获取边缘上的位置
            const tmpPoint = shape.getPoint(ratio);
            // 在此处返回修改后的配置，在此处返回 x 和 y
            return {
              x: tmpPoint.x,
              y: tmpPoint.y,
            };
          },
          {
            repeat: true, // 是否重复执行动画
            duration: 3000, // 执行一次的持续时间
          }
        );
      },
    },
    'cubic' // 扩展内置边
  );
}

/**
 * line 直线，含有状态动画
 * @key line-animate-state
 * @name selected 选中状态
 * @name circle-move 圆点沿边运动
 * @name line-dash 虚线运动
 * @name line-path 线路径加载运动
 */
export function edgeLineAnimateState() {
  registerEdge(
    'line-animate-state',
    {
      setState: (name, value, item: any) => {
        const group = item.get('group');
        const model = item.getModel();
        const keyShape = group.find(
          (ele: any) => ele.get('name') === 'edge-shape'
        );

        // selected 选中状态
        if (name === 'selected') {
          if (value) {
            const { lineWidth, stroke, shadowBlur, shadowColor } =
              item.getStateStyle('selected');
            keyShape.attr({
              lineWidth,
              stroke,
              shadowBlur,
              shadowColor,
            });
          } else {
            const { lineWidth, stroke } = model.style;
            keyShape.attr({
              lineWidth,
              stroke,
              shadowBlur: null,
              shadowColor: null,
            });
          }
          return;
        }

        // circle-move 圆点沿边运动
        if (name === 'circle-move') {
          let back1 = group.find(
            (ele: any) => ele.get('name') === 'circle-stroke1'
          );
          if (back1) {
            back1.remove();
            back1.destroy();
          }
          let back2 = group.find(
            (ele: any) => ele.get('name') === 'circle-stroke2'
          );
          if (back2) {
            back2.remove();
            back2.destroy();
          }
          if (value) {
            // 第一个矩形边
            const fillColor = model?.labelCfg?.style?.fill || '#1890ff';
            // 边缘路径的起始位置
            const startPoint = keyShape.getPoint(0);
            back1 = group.addShape('circle', {
              attrs: {
                x: startPoint.x,
                y: startPoint.y,
                fill: fillColor,
                r: 3,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'circle-stroke1',
            });
            back1.animate(
              (ratio: any) => {
                // 每帧中的操作。比率范围从 0 到 1，表示动画的进度。返回修改后的配置
                // 根据比率获取边缘上的位置
                const tmpPoint = keyShape.getPoint(ratio);
                // 在此处返回修改后的配置，在此处返回 x 和 y
                return {
                  x: tmpPoint.x,
                  y: tmpPoint.y,
                };
              },
              {
                repeat: true, // 是否重复执行动画
                duration: 3 * 1000, // 执行一次的持续时间
              }
            );
            // 第二个矩形边
            const endPoint = keyShape.getPoint(1);
            back2 = group.addShape('circle', {
              zIndex: -2,
              attrs: {
                x: endPoint.x,
                y: endPoint.y,
                fill: fillColor,
                r: 3,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'circle-stroke2',
            });

            back2.animate(
              (ratio: any) => {
                // 每帧中的操作。比率范围从 0 到 1，表示动画的进度。返回修改后的配置
                // 根据比率获取边缘上的位置
                const tmpPoint = keyShape.getPoint(1 - ratio);
                // 在此处返回修改后的配置，在此处返回 x 和 y
                return {
                  x: tmpPoint.x,
                  y: tmpPoint.y,
                };
              },
              {
                repeat: true, // 是否重复执行动画
                duration: 2 * 1000, // 执行一次的持续时间
              }
            );
          }
          return;
        }
 
        // line-dash 虚线运动
        if (name === 'line-dash') {
          if (value) {
            if (keyShape.cfg.animating) return;
            let index = 0;
            keyShape.animate(
              () => {
                index++;
                if (index > 8) {
                  index = 0;
                }
                return {
                  lineDash: [4, 2, 1, 2],
                  lineDashOffset: -index,
                };
              },
              {
                repeat: true, // 是否重复执行动画
                duration: 3000, // 执行一次的持续时间
              }
            );
          } else {
            keyShape.stopAnimate();
            keyShape.attr({
              lineDash: null,
              lineDashOffset: null,
            });
          }
          return;
        }

        // line-path 线路径加载运动
        if (name === 'line-path') {
          // 线路径
          let back = group.find((ele: any) => ele.get('name') === 'line-path');
          if (back) {
            back.remove();
            back.destroy();
          }
          const { path, stroke, lineWidth } = keyShape.attr();
          back = group.addShape('path', {
            attrs: {
              path,
              stroke,
              lineWidth,
              opacity: 0.2,
            },
            name: 'line-path',
          });
          back.toBack(); // 置于底层

          if (value) {
            if (keyShape.cfg.animating) return;
            // 直线加载
            const length = keyShape.getTotalLength();
            keyShape.animate(
              (ratio: any) => {
                const startLen = ratio * length;
                return {
                  lineDash: [startLen, length - startLen],
                };
              },
              {
                repeat: true,
                duration: 2000,
              }
            );
          } else {
            keyShape.stopAnimate();
            keyShape.attr({
              lineDash: null,
            });
            back.remove();
            back.destroy();
          }
          return;
        }
      },
    },
    'line' // 扩展内置边
  );
}
