import React, { useState, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';

import Outer from '../OuterRectForLine';
import { parsePositionForBackend } from '../../helpers/position';

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

import { SVG } from './styled';

const getActualPoint = (
  { start, end }: LinePositionType,
  h: number,
  s: number,
): LinePositionType => {
  const x1 = start.x * s;
  const y1 = h - start.y * s;
  const x2 = end.x * s;
  const y2 = h - end.y * s;
  return {
    start: {
      x: x1,
      y: y1,
    },
    end: {
      x: x2,
      y: y2,
    },
  };
};

const rectCalc = ({ start, end }: LinePositionType): HTMLCoordinateType => {
  return {
    top: start.y < end.y ? start.y : end.y,
    left: start.x < end.x ? start.x : end.x,
    width: Math.abs(end.x - start.x),
    height: Math.abs(end.y - start.y),
  };
};

const Line: React.FC<AnnotationElementPropsType> = ({
  id,
  obj_type,
  obj_attr: { bdcolor = '', bdwidth = 0, transparency = 0, position, is_arrow },
  scale,
  viewport,
  isCollapse,
  onUpdate,
}: AnnotationElementPropsType) => {
  const [startPoint, setStartPoint] = useState({ x: 0, y: 0 });
  const [endPoint, setEndPoint] = useState({ x: 0, y: 0 });
  const [rect, setRect] = useState({ top: 0, left: 0, width: 0, height: 0 });
  const [moving, setMoving] = useState(false);
  const uuid = uuidv4();

  const actualbdwidth = bdwidth * scale;

  const handleMove = ({
    start: moveStart,
    end: moveEnd,
  }: LinePositionType): void => {
    setMoving(true);
    setStartPoint(moveStart);
    setEndPoint(moveEnd);

    const newRect = rectCalc({ start: moveStart, end: moveEnd });

    if (is_arrow) {
      setRect({
        top: newRect.top - actualbdwidth * 2,
        left: newRect.left - actualbdwidth * 2,
        width: newRect.width + actualbdwidth * 4,
        height: newRect.height + actualbdwidth * 4,
      });
    } else {
      setRect({
        top: newRect.top - actualbdwidth / 2,
        left: newRect.left - actualbdwidth / 2,
        width: newRect.width + actualbdwidth,
        height: newRect.height + actualbdwidth,
      });
    }
  };

  const handleMouseUp = () => {
    setMoving(false);
  };

  useEffect(() => {
    if (!moving && startPoint.x) {
      const newPosition = {
        start: {
          x: startPoint.x,
          y: startPoint.y,
        },
        end: {
          x: endPoint.x,
          y: endPoint.y,
        },
      };

      onUpdate({
        position: parsePositionForBackend(
          obj_type,
          newPosition,
          viewport.height,
          scale,
        ),
      });
    }
  }, [moving, startPoint, endPoint]);

  useEffect(() => {
    const { start, end } = getActualPoint(
      position as LinePositionType,
      viewport.height,
      scale,
    );

    setStartPoint(start);
    setEndPoint(end);

    const initRect = rectCalc({ start, end });

    if (is_arrow) {
      setRect({
        top: initRect.top - actualbdwidth * 2,
        left: initRect.left - actualbdwidth * 2,
        width: initRect.width + actualbdwidth * 4,
        height: initRect.height + actualbdwidth * 4,
      });
    } else {
      setRect({
        top: initRect.top - actualbdwidth / 2,
        left: initRect.left - actualbdwidth / 2,
        width: initRect.width + actualbdwidth,
        height: initRect.height + actualbdwidth,
      });
    }
  }, [viewport, scale]);

  return (
    <>
      <AnnotationContainer
        id={id}
        top={`${rect.top}px`}
        left={`${rect.left}px`}
        width={`${rect.width}px`}
        height={`${rect.height}px`}
      >
        <SVG
          width={rect.width}
          height={rect.height}
          viewBox={`${rect.left} ${rect.top} ${rect.width} ${rect.height}`}
        >
          {is_arrow ? (
            <defs>
              <marker
                id={uuid}
                markerWidth={actualbdwidth * 2}
                markerHeight={actualbdwidth * 3}
                refX={3}
                refY={2}
                orient="auto"
                markerUnits="strokeWidth"
              >
                <polyline
                  points="0.25,0.5 3.25,2 0.25,3.5 3.25,2 -0.25,2"
                  stroke={bdcolor}
                  strokeWidth={1}
                  fill="none"
                  strokeDasharray={100}
                />
              </marker>
            </defs>
          ) : null}
          <line
            x1={startPoint.x}
            y1={startPoint.y}
            x2={endPoint.x}
            y2={endPoint.y}
            stroke={bdcolor}
            strokeWidth={actualbdwidth}
            strokeOpacity={transparency}
            markerEnd={is_arrow ? `url(#${uuid})` : ''}
          />
        </SVG>
      </AnnotationContainer>
      {!isCollapse ? (
        <Outer
          top={rect.top}
          left={rect.left}
          width={rect.width}
          height={rect.height}
          start={startPoint}
          end={endPoint}
          onMove={handleMove}
          onMouseUp={handleMouseUp}
        />
      ) : (
        ''
      )}
    </>
  );
};

export default Line;
