import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { Texture } from 'fabric-texture';
import Skew from 'fabric-texture/modes/skew'
import Perspective from 'fabric-texture/modes/perspective'
import Warp from 'fabric-texture/modes/warp'
import styles from './style.less';
import { DocsContext } from 'docs/docs';

/**
 * 创建倾斜图
 */
const createSkewImage = (image: HTMLImageElement) => {
  const texture = new Texture(image);

  texture
    .setSplitUnit(1)
    .setSplitStrategy({
      name: 'skew',
      execute: Skew.execute,
    })
    .setVertexCoord(0, 0, 'tl', { x: image.naturalWidth * 0.2, y: 0 })
    .setVertexCoord(0, 0, 'tr', { x: image.naturalWidth * 1.2, y: 0 });

  const canvas = texture.create();

  return new Promise<string>((resolve) => {
    canvas.toBlob((blob) => {
      if (blob) {
        const url = URL.createObjectURL(blob);
        resolve(url);
      }
    });
  });
};

/**
 * 创建透视图
 */
const createPerspectiveImage = (image: HTMLImageElement) => {
  const texture = new Texture(image);

  // 透视
  texture
    .setSplitUnit(0.01)
    .setSplitStrategy({
      name: 'perspective',
      execute: Perspective.execute,
    })
    .setVertexCoord(0, 0, 'tr', { x: image.naturalWidth, y: image.naturalHeight / 3 })
    .setVertexCoord(0, 0, 'br', { x: image.naturalWidth, y: image.naturalHeight * (2 / 3) });

  const canvas = texture.create();

  return new Promise<string>((resolve) => {
    canvas.toBlob((blob) => {
      if (blob) {
        const url = URL.createObjectURL(blob);
        resolve(url);
      }
    });
  });
};

/**
 * 创建扭曲图
 */
const createWarpImage = (image: HTMLImageElement) => {
  const texture = new Texture(image);

  texture
    .setSplitUnit(0.01)
    .setSplitStrategy({
      name: 'warp',
      execute: Warp.execute,
    })
    .setBoundCoords(0, 0, 'top', [
      { x: 0, y: 0 },
      { x: image.naturalWidth / 3, y: image.naturalHeight * 0.2 },
      { x: image.naturalWidth * (2 / 3), y: image.naturalHeight * 0.2 },
      { x: image.naturalWidth, y: 0 },
    ])
    .setBoundCoords(0, 0, 'bottom', [
      { x: 0, y: image.naturalHeight },
      { x: image.naturalWidth / 3, y: image.naturalHeight * 0.8 },
      { x: image.naturalWidth * (2 / 3), y: image.naturalHeight * 0.8 },
      { x: image.naturalWidth, y: image.naturalHeight },
    ]);

  const canvas = texture.create();

  return new Promise<string>((resolve) => {
    canvas.toBlob((blob) => {
      if (blob) {
        const url = URL.createObjectURL(blob);
        resolve(url);
      }
    });
  });
};

function EffectImages() {
  const { placeholder } = useContext(DocsContext);
  const [skewImageUrl, setSkewImageUrl] = useState<string>();
  const [perspectiveImageUrl, setPerspectiveImageUrl] = useState<string>();
  const [warpImageUrl, setWarpImageUrl] = useState<string>();

  const run = useCallback(async (image: HTMLImageElement) => {
    setSkewImageUrl(await createSkewImage(image));
    setPerspectiveImageUrl(await createPerspectiveImage(image));
    setWarpImageUrl(await createWarpImage(image));
  }, []);

  useEffect(() => {
    if (placeholder) run(placeholder);
  }, [placeholder]);

  const images = useMemo(() => {
    return [
      {
        label: 'Origin',
        labelCn: '原图',
        url: placeholder?.currentSrc,
      },
      {
        label: 'Skew',
        labelCn: '倾斜',
        url: skewImageUrl,
      },
      {
        label: 'Perspective',
        labelCn: '透视',
        url: perspectiveImageUrl,
      },
      {
        label: 'Warp',
        labelCn: '扭曲',
        url: warpImageUrl,
      },
    ];
  }, [skewImageUrl, perspectiveImageUrl, warpImageUrl]);

  if (images.some((i) => !i.url)) return null;

  return (
    <div className={styles.demo}>
      {images.map((image) => (
        <div className={styles.box}>
          <div className={styles.image}>
            <img src={image.url} />
          </div>
          <div className={styles.label}>
            {image.label}
            <br />
            <span>({image.labelCn})</span>
          </div>
        </div>
      ))}
    </div>
  );
}

export default EffectImages;
