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

import { ANNOTATION_TYPE } from '../constants';
import Icon from '../components/Icon';
import Button from '../components/Button';
import ExpansionPanel from '../components/ExpansionPanel';
import InkOption from '../components/InkOption';

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

import { getAbsoluteCoordinate } from '../helpers/position';
import {
  parseAnnotationObject,
  appendUserIdAndDate,
} from '../helpers/annotation';
import { switchPdfViewerScrollState } from '../helpers/pdf';
import useCursorPosition from '../hooks/useCursorPosition';

import useActions from '../actions';
import useStore from '../store';

type Props = {
  title: string;
  isActive: boolean;
  onClick: () => void;
};

let pathEle: any = null;

const FreehandTool: React.FC<Props> = ({ title, isActive, onClick }: Props) => {
  const [cursorPosition, setRef] = useCursorPosition(30);

  const [path, setPath] = useState<PointType[]>([]);
  const [data, setData] = useState({
    page: 0,
    type: 'pen',
    opacity: 100,
    color: '#FF0000',
    width: 3,
  });
  const [{ viewport, scale }, dispatch] = useStore();
  const { addAnnots } = useActions(dispatch);

  const setDataState = (obj: OptionPropsType): void => {
    setData((prev) => ({
      ...prev,
      ...obj,
    }));
  };

  const handleMouseDown = (event: MouseEvent | TouchEvent): void => {
    const pageEle = (event.target as HTMLElement).parentNode as HTMLElement;
    switchPdfViewerScrollState('hidden');

    if (pageEle.hasAttribute('data-page-num')) {
      setRef(pageEle);
      const pageNum = pageEle.getAttribute('data-page-num') || '0';
      const coordinate = getAbsoluteCoordinate(pageEle, event);
      setData((current) => ({
        ...current,
        page: parseInt(pageNum, 10),
      }));
      setPath([coordinate]);
    }
  };

  const handleMouseUp = useCallback((): void => {
    switchPdfViewerScrollState('scroll');
    const id = uuidv4();

    if (path.length) {
      const defaultPoints = [
        { x: path[0].x - 3, y: path[0].y - 3 },
        { x: path[0].x + 3, y: path[0].y + 3 },
      ];

      const annotData = {
        id,
        obj_type: ANNOTATION_TYPE.ink,
        obj_attr: {
          page: data.page as number,
          bdcolor: data.color,
          bdwidth: data.width,
          position: path.length === 1 ? [defaultPoints] : [path],
          transparency: data.opacity,
        },
      };
      const freehand = appendUserIdAndDate(
        parseAnnotationObject(annotData, viewport.height, scale),
      );

      addAnnots([freehand]);
      setRef(null);
      setPath([]);
    }
  }, [path, data, viewport, scale]);

  useEffect(() => {
    if (cursorPosition.x && cursorPosition.y) {
      const coordinates = {
        x: cursorPosition.x,
        y: cursorPosition.y,
      } as PointType;

      setPath((current) => {
        return [...current, coordinates];
      });
    }
  }, [cursorPosition]);

  /**
   * 1. draw to canvas when mouse move
   * 2. trigger mouse up to remove path element
   */
  useEffect(() => {
    const pageEle = document.getElementById(`page_${data.page}`);
    const canvas = pageEle?.getElementsByClassName('canvas')[0] as HTMLElement;

    if (path.length) {
      if (pageEle && canvas) {
        canvas.style.display = 'block';

        if (pathEle) {
          const d = svgPath(path, bezierCommand(controlPoint(line, 0.2)));
          pathEle.setAttribute('d', d);
        } else {
          pathEle = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'path',
          );
          pathEle.setAttribute('fill', 'none');
          pathEle.setAttribute('stroke', data.color);
          pathEle.setAttribute('stroke-width', data.width * scale);
          pathEle.setAttribute('stroke-opacity', data.opacity * 0.01);
          canvas.appendChild(pathEle);
        }
      }
    } else if (canvas && pathEle) {
      canvas.style.display = 'none';
      canvas.removeChild(pathEle);
      pathEle = null;
    }
  }, [path, data, scale]);

  const subscribeEvent = (): void => {
    const pdfViewer = document.getElementById('pdf_viewer') as HTMLDivElement;

    pdfViewer.addEventListener('mousedown', handleMouseDown);
    pdfViewer.addEventListener('mouseup', handleMouseUp);
    pdfViewer.addEventListener('touchstart', handleMouseDown);
    pdfViewer.addEventListener('touchend', handleMouseUp);
  };

  const unsubscribeEvent = (): void => {
    const pdfViewer = document.getElementById('pdf_viewer') as HTMLDivElement;

    pdfViewer.removeEventListener('mousedown', handleMouseDown);
    pdfViewer.removeEventListener('mouseup', handleMouseUp);
    pdfViewer.removeEventListener('touchstart', handleMouseDown);
    pdfViewer.removeEventListener('touchend', handleMouseUp);
  };

  useEffect(() => {
    const pdfViewer = document.getElementById('pdf_viewer') as HTMLDivElement;

    if (isActive && pdfViewer) {
      subscribeEvent();
    }

    return (): void => {
      if (pdfViewer) {
        unsubscribeEvent();
      }
    };
  }, [isActive, handleMouseUp]);

  const Label = (
    <Button
      shouldFitContainer
      align="left"
      onClick={onClick}
      isActive={isActive}
    >
      <Icon glyph="freehand" style={{ marginRight: '10px' }} />
      {title}
    </Button>
  );

  return (
    <ExpansionPanel label={Label} isActive={isActive} showBottomBorder>
      <InkOption
        type={data.type}
        color={data.color}
        opacity={data.opacity}
        width={data.width}
        setDataState={setDataState}
      />
    </ExpansionPanel>
  );
};

export default FreehandTool;
