import React from 'react';

import {
  AnnotationElementPropsType,
  PointType,
  HTMLCoordinateType,
  CoordType,
  UpdateData,
} from '../../constants/type';
import OuterRect from '../OuterRect';
import {
  svgPath,
  bezierCommand,
  controlPoint,
  line,
} from '../../helpers/svgBezierCurve';

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

const Ink: React.SFC<AnnotationElementPropsType> = ({
  obj_attr: { position, bdcolor, bdwidth = 0, transparency },
  isCollapse,
  onUpdate,
  viewport,
  scale,
  id,
}: AnnotationElementPropsType) => {
  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[][],
    borderWidth: number
  ): 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,
    };
  };

  const borderWidth = bdwidth * scale;
  const annotPoints = pointCalc(
    position as PointType[][],
    viewport.height,
    scale
  );
  const annotRect = rectCalcWithPoint(annotPoints, borderWidth);

  const scaleOrMoveCalc = (
    rect: HTMLCoordinateType,
    updatePoints: (data: UpdateData) => void
  ) => ({ 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),
    }));

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

  const handleScaleOrMove = scaleOrMoveCalc(annotRect, onUpdate);

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

  return (
    <>
      <AnnotationContainer
        top={`${annotRect.top}px`}
        left={`${annotRect.left}px`}
        width={`${annotRect.width}px`}
        height={`${annotRect.height}px`}
      >
        <SVG viewBox={calcViewBox(annotRect, bdwidth * scale)}>
          {annotPoints.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={annotRect.top}
          left={annotRect.left}
          width={annotRect.width}
          height={annotRect.height}
          onMove={handleScaleOrMove}
          onScale={handleScaleOrMove}
        />
      ) : (
        ''
      )}
    </>
  );
};

export default Ink;
