import React, { useState } from 'react';

import OuterRect from '../OuterRect';
import {
  svgPath,
  bezierCommand,
  controlPoint,
  line,
} from '../../helpers/svgBezierCurve';

import { AnnotationContainer } from '../../global/otherStyled';
import { SVG } from './styled';

let points: PointType[][] = [];
let rect: HTMLCoordinateType = { top: 0, left: 0, width: 0, height: 0 };

const Ink: React.FC<AnnotationElementPropsType> = ({
  obj_attr: { position, bdcolor, bdwidth = 0, transparency },
  isCollapse,
  onUpdate,
  viewport,
  scale,
  id,
}: AnnotationElementPropsType) => {
  const borderWidth = bdwidth * scale;

  const pointCalc = (
    _points: PointType[][],
    h: number,
    s: number,
  ): PointType[][] => {
    const reducer = _points.reduce(
      (acc: PointType[][], cur: PointType[]): PointType[][] => {
        const p = cur.map((point: PointType) => ({
          x: point.x * s,
          y: h - point.y * s,
        }));
        acc.push(p);
        return acc;
      },
      [],
    );

    return reducer;
  };

  const rectCalcWithPoint = (
    pointsGroup: PointType[][],
  ): HTMLCoordinateType => {
    const xArray: number[] = [];
    const yArray: number[] = [];
    pointsGroup[0].forEach((point: PointType) => {
      xArray.push(point.x);
      yArray.push(point.y);
    });
    const top = Math.min(...yArray);
    const left = Math.min(...xArray);
    const bottom = Math.max(...yArray);
    const right = Math.max(...xArray);
    return {
      top,
      left,
      width: right - left + borderWidth,
      height: bottom - top + borderWidth,
    };
  };

  points = pointCalc(position as PointType[][], viewport.height, scale);
  rect = rectCalcWithPoint(points);

  const [newRect, setRect] = useState({ top: 0, left: 0, width: 0, height: 0 });

  const handleScaleOrMove = ({
    top,
    left,
    width = 0,
    height = 0,
  }: CoordType): void => {
    const xScaleRate = width / rect.width;
    const yScaleRate = height / rect.height;
    const xDistance = left - rect.left;
    const yDistance = rect.top - top;

    const newPosition = (position as PointType[][])[0].map((ele) => ({
      x: (ele.x + xDistance) * (xScaleRate || 1),
      y: (ele.y + yDistance) * (yScaleRate || 1),
    }));

    rect = { top, left, width, height };
    setRect({
      top,
      left,
      width,
      height,
    });

    onUpdate({
      position: [newPosition],
    });
  };

  const calcViewBox = (
    { top, left, width, height }: HTMLCoordinateType,
    _borderWidth: number,
  ): string => `
    ${left - _borderWidth / 2} ${top - _borderWidth / 2} ${width} ${height}
  `;

  return (
    <>
      <AnnotationContainer
        id={id}
        top={`${newRect.top || rect.top}px`}
        left={`${newRect.left || rect.left}px`}
        width={`${newRect.width || rect.width}px`}
        height={`${newRect.height || rect.height}px`}
      >
        <SVG viewBox={calcViewBox(rect, bdwidth * scale)}>
          {points.map((ele: PointType[], index: number) => {
            const key = `${id}_path_${index}`;
            return (
              <path
                key={key}
                d={svgPath(
                  ele as PointType[],
                  bezierCommand(controlPoint(line, 0.2)),
                )}
                fill="none"
                stroke={bdcolor}
                strokeWidth={bdwidth * scale}
                strokeOpacity={transparency}
              />
            );
          })}
        </SVG>
      </AnnotationContainer>
      {!isCollapse ? (
        <OuterRect
          top={newRect.top || rect.top}
          left={newRect.left || rect.left}
          width={newRect.width || rect.width}
          height={newRect.height || rect.height}
          onMove={handleScaleOrMove}
          onScale={handleScaleOrMove}
        />
      ) : (
        ''
      )}
    </>
  );
};

export default Ink;
