import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { fabric } from 'fabric';
import { FabricTexture } 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 { Canvas, Code, TextValue } from 'docs/components';
import type { CanvasHandlers } from 'docs/components/canvas';
import { DocsContext } from 'docs/docs';
import styles from './style.less';

const modes = {
  Skew,
  Perspective,
  Warp,
}

const LimitTextureInputSize = () => {
  const { placeholder } = useContext(DocsContext);

  const _canvasRef = useRef<CanvasHandlers>(null);
  const _fabricTextureRef = useRef<FabricTexture>();

  const [inputWidth, setInputWidth] = useState<number>(2000);
  const [inputHeight, setInputHeight] = useState<number>(2000);

  const render = useCallback(async () => {
    const canvas = _canvasRef.current?.getCanvas();
    if (!canvas) return;

    const width = canvas.getWidth();
    const height = canvas.getHeight();

    if (!placeholder) return;

    // 缩放以控制在合理渲染区域内
    const scale =
      Math.min(200, canvas.getWidth()) /
      Math.min(placeholder.naturalWidth, placeholder.naturalHeight);

    // 创建元素
    const object = new fabric.Image(placeholder, {
      left: width / 2,
      top: height / 2,
      scaleX: scale,
      scaleY: scale,
      originX: 'center',
      originY: 'center',
    });

    // 如果已存在则先结束上一轮编辑
    if (_fabricTextureRef.current) {
      _fabricTextureRef.current.leaveEditing();
    }

    // 进入交互态
    const fabricTexture = new FabricTexture(canvas, { history: true });
    fabricTexture.enterEditing(object, null, new modes.Perspective(), (texture) => {
      texture.setInputLimitSize({
        width: inputWidth,
        height: inputHeight,
      });
    });
    _fabricTextureRef.current = fabricTexture;

    // 隐藏源元素
    object.set({ visible: false });
    canvas.renderAll();
  }, [placeholder]);

  useEffect(() => {
    render();
  }, [render]);

  const changeLimitSize = useCallback(
    (type: 'width' | 'height') => {
      return (value: number) => {
        const fabricTexture = _fabricTextureRef.current;
        if (!fabricTexture) return;

        fabricTexture.texture?.setInputLimitSize({
          width: inputWidth,
          height: inputHeight,
          [type]: value,
        });

        fabricTexture.requestRender();

        // 同步参数
        ({ width: setInputWidth, height: setInputHeight })[type](value);
      };
    },
    [inputWidth, inputHeight],
  );

  return (
    <div className={styles.demo}>
      <Canvas className={styles.canvas} ref={_canvasRef} />
      <Code
        className={styles.code}
        lineCount={18}
        link="sections/more-configuration/codes/limit-texture-input-size-demo.ts"
      >
        {(key) => {
          switch (key) {
            case 'input-width':
              return (
                <TextValue
                  value={inputWidth}
                  min={0}
                  max={9999}
                  onChange={changeLimitSize('width')}
                />
              );
            case 'input-height':
              return (
                <TextValue
                  value={inputHeight}
                  min={0}
                  max={9999}
                  onChange={changeLimitSize('height')}
                />
              );
          }
        }}
      </Code>
    </div>
  );
};

export default LimitTextureInputSize;
