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

/**
 * cubic 圆形，节点放大缩小动画
 * @type circle-animate-shape-r
 */
export function nodeCircleAnimateShapeR() {
  registerNode(
    'circle-animate-shape-r',
    {
      afterDraw(cfg, group) {
        if (!group) return;
        const shape = group.get('children')[0];
        const r = Number(cfg?.size) || 2;
        shape.animate(
          (ratio: any) => {
            const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10;
            return {
              r: r / 2 + diff,
            };
          },
          {
            repeat: true, // 是否重复执行动画
            duration: 3000, // 执行一次的持续时间
            easing: 'easeCubic',
          }
        );
      },
    },
    'circle'
  );
}

/**
 * cubic 圆形，节点边缘扩散动画
 * @type circle-animate-shape-stroke
 */
export function nodeCircleAnimateShapeStroke() {
  registerNode(
    'circle-animate-shape-stroke',
    {
      afterDraw(cfg, group) {
        if (!group) return;

        const size = Array.isArray(cfg?.size) ? cfg?.size[0] : cfg?.size;
        let r = Number(size) || 2;
        r = r / 2;

        const fillColor = cfg?.style?.fill || '#1890ff';

        // 第一个背景圆
        const back1 = group.addShape('circle', {
          zIndex: -3,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: fillColor,
            opacity: 0.6,
          },
          // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
          name: 'circle-shape1',
        });
        // 第二个背景圆
        const back2 = group.addShape('circle', {
          zIndex: -2,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: fillColor,
            opacity: 0.6,
          },
          // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
          name: 'circle-shape2',
        });
        // 第三个背景圆
        const back3 = group.addShape('circle', {
          zIndex: -1,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: fillColor,
            opacity: 0.6,
          },
          // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
          name: 'circle-shape3',
        });
        group.sort(); // 排序，根据 zIndex 排序

        // 第一个背景圆逐渐放大，并消失
        back1.animate(
          {
            r: r + 10,
            opacity: 0.1,
          },
          {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: 0, // 无延迟
          }
        );

        // 第二个背景圆逐渐放大，并消失
        back2.animate(
          {
            r: r + 10,
            opacity: 0.1,
          },
          {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: 1000, // 1 秒延迟
          }
        );

        // 第三个背景圆逐渐放大，并消失
        back3.animate(
          {
            r: r + 10,
            opacity: 0.1,
          },
          {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: 2000, // 2 秒延迟
          }
        );
      },
    },
    'circle'
  );
}

/**
 * rect 矩形，含有状态动画
 * @key rect-animate-state
 * @name selected 选中状态
 * @name stroke 边缘扩散状态
 */
export function nodeRectAnimateState() {
  registerNode(
    'rect-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') === 'rect-animate-state-keyShape'
        );

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

        // stroke 边缘扩散状态
        if (name === 'stroke') {
          // 矩形边元素需要移除，请在设置状态前判断是否已设置
          const backArr: any[] = group.findAll((ele: any) =>
            ele.get('name').startsWith('rect-stroke')
          );

          if (value) {
            if (Array.isArray(backArr) && backArr.length === 3) return;
            const size = Array.isArray(model?.size) ? model?.size : [40, 40];
            const { fill, lineWidth, stroke, radius } = model.style;
            const fillColor = fill || stroke;
            // 第一个矩形边
            const back1 = group.addShape('rect', {
              zIndex: -3,
              attrs: {
                x: -size[0] / 2,
                y: -size[1] / 2,
                width: size[0],
                height: size[1],
                stroke: fillColor,
                lineWidth: lineWidth,
                radius: radius,
                strokeOpacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'rect-stroke1',
            });
            backArr.push(back1);
            // 第二个矩形边
            const back2 = group.addShape('rect', {
              zIndex: -2,
              attrs: {
                x: -size[0] / 2,
                y: -size[1] / 2,
                width: size[0],
                height: size[1],
                stroke: fillColor,
                lineWidth: lineWidth,
                radius: radius,
                opacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'rect-stroke2',
            });
            backArr.push(back2);
            // 第三个矩形边
            const back3 = group.addShape('rect', {
              zIndex: -1,
              attrs: {
                x: -size[0] / 2,
                y: -size[1] / 2,
                width: size[0],
                height: size[1],
                stroke: fillColor,
                lineWidth: lineWidth,
                radius: radius,
                opacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'rect-stroke3',
            });
            backArr.push(back3);

            for (let i = 0; i < backArr.length; i++) {
              const back = backArr[i];
              back.show();
              back.animate(
                {
                  stroke: fillColor,
                  lineWidth: lineWidth + 12, // 边宽度
                  strokeOpacity: 0.1,
                },
                {
                  repeat: true, // 循环
                  duration: 3000,
                  easing: 'easeCubic',
                  delay: i * 1000, // 逐渐延迟
                }
              );
            }
          } else {
            if (Array.isArray(backArr) && backArr.length === 0) return;
            for (const back of backArr) {
              back.stopAnimate();
              back.hide();
              back.remove();
              back.destroy();
            }
          }
          return;
        }
      },
    },
    'rect'
  );
}

/**
 * image 图片，含有状态动画
 * @key image-animate-state
 * @name top-right-dot 右上角圆点状态
 */
export function nodeImageAnimateState() {
  registerNode(
    'image-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') === 'image-animate-state-keyShape'
        // );

        // selected 选中状态
        if (name === 'selected') {
          return;
        }

        // top-right-dot 右上角圆点状态
        if (name === 'top-right-dot') {
          // 矩形边元素需要移除，请在设置状态前判断是否已设置
          const backArr: any[] = group.findAll((ele: any) =>
            ele.get('name').startsWith('circle-shape')
          );
          if (value) {
            if (Array.isArray(backArr) && backArr.length === 3) return;
            const size = Array.isArray(model?.size) ? model?.size : [40, 40];
            const x = size[0] / 2;
            const y = -size[1] / 2;
            const r = 3;
            const fillColor = typeof value === 'string' ? value : '#f5222d';

            // 第一个背景圆
            const back1 = group.addShape('circle', {
              zIndex: -3,
              attrs: {
                x,
                y,
                r,
                fill: fillColor,
                opacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'circle-shape1',
            });
            backArr.push(back1);
            // 第二个背景圆
            const back2 = group.addShape('circle', {
              zIndex: -2,
              attrs: {
                x,
                y,
                r,
                fill: fillColor,
                opacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'circle-shape2',
            });
            backArr.push(back2);
            // 第三个背景圆
            const back3 = group.addShape('circle', {
              zIndex: -1,
              attrs: {
                x,
                y,
                r,
                fill: fillColor,
                opacity: 0.6,
              },
              // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
              name: 'circle-shape3',
            });
            backArr.push(back3);

            for (let i = 0; i < backArr.length; i++) {
              const back = backArr[i];
              back.show();
              back.animate(
                {
                  r: 6,
                  opacity: 0.3,
                },
                {
                  repeat: true, // 循环
                  duration: 3000,
                  easing: 'easeCubic',
                  delay: i * 1000, // 逐渐延迟
                }
              );
            }
          } else {
            if (Array.isArray(backArr) && backArr.length === 0) return;
            for (const back of backArr) {
              back.stopAnimate();
              back.hide();
              back.remove();
              back.destroy();
            }
          }
          return;
        }
      },
    },
    'image'
  );
}
