import Konva from 'konva';
import React from 'react';
import { KonvaNodeComponent, Transformer } from 'react-konva';
import { TransformableShapeProps } from '../types';

export function withTransform<
  TShapeComponent extends KonvaNodeComponent<Konva.Node>,
>(Shape: TShapeComponent) {
  return function ({
    isTransformable,
    isSelected,
    onSelect,
    onChange,
    title,
    isAnchor,
    ...shapeProps
  }: TransformableShapeProps<TShapeComponent>) {
    const labelRef = React.useRef<Konva.Label>();
    const shapeRef = React.useRef<Konva.Node>();
    const tranformRef = React.useRef<Konva.Transformer>();

    React.useEffect(() => {
      if (isSelected) {
        const nodes = [shapeRef.current, labelRef.current].filter(Boolean);
        tranformRef.current.nodes(nodes);
        tranformRef.current.getLayer().batchDraw();
      }
    }, [isSelected]);

    return (
      <>
        {/* @ts-ignore */}
        <Shape
          ref={shapeRef}
          {...shapeProps}
          strokeScaleEnabled={false}
          draggable={isTransformable}
          onClick={onSelect}
          onTap={onSelect}
          onDragEnd={(e) => {
            onChange({
              ...shapeProps,
              x: e.target.x(),
              y: e.target.y(),
            });
          }}
          onTransform={(event) => {
            const textNode = labelRef.current;
            if (textNode) {
              const stageScale = event.currentTarget.getStage().scale().x;

              const absScale = labelRef.current?.getAbsoluteScale() || {
                x: 1,
                y: 1,
              };
              textNode.scaleX((textNode.scaleX() / absScale.x) * stageScale);
              textNode.scaleY((textNode.scaleY() / absScale.y) * stageScale);
            }
          }}
          onTransformEnd={() => {
            const node = shapeRef.current;
            const scaleX = node.scaleX();
            const scaleY = node.scaleY();

            node.scaleX(1);
            node.scaleY(1);
            onChange({
              ...shapeProps,
              x: node.x(),
              y: node.y(),
              width: Math.max(5, node.width() * scaleX),
              height: Math.max(node.height() * scaleY),
            });
          }}
          fill={isSelected ? shapeProps.fill : null}
        />
        {isSelected && (
          <Transformer
            ref={tranformRef}
            ignoreStroke
            boundBoxFunc={(oldBox, newBox) => {
              if (newBox.width < 5 || newBox.height < 5) {
                return oldBox;
              }
              return newBox;
            }}
            draggable={isTransformable}
            resizeEnabled={isTransformable}
            rotateEnabled={isTransformable}
          />
        )}
      </>
    );
  };
}
