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 {
  getAbsoluteCoordinate,
  parsePositionForBackend,
} from '../helpers/position';
import { parseAnnotationObject } from '../helpers/annotation';
import useCursorPosition from '../hooks/useCursorPosition';

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

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

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

  const [uuid, setUuid] = useState('');
  const [data, setData] = useState({
    type: 'pen',
    opacity: 100,
    color: '#FCFF36',
    width: 12,
  });
  const [{ viewport, scale, annotations }, dispatch] = useStore();
  const { addAnnots, updateAnnots } = useActions(dispatch);

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

  const handleMouseDown = useCallback(
    (e: MouseEvent | TouchEvent): void => {
      const pageEle = (e.target as HTMLElement).parentNode as HTMLElement;

      if (pageEle.hasAttribute('data-page-num')) {
        setRef(pageEle);
        const pageNum = pageEle.getAttribute('data-page-num') || 0;
        const coordinate = getAbsoluteCoordinate(pageEle, e);
        const id = uuidv4();

        setUuid(id);

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

        addAnnots([freehand]);
      }
    },
    [data, viewport, scale]
  );

  const handleMouseUp = useCallback((): void => {
    const index = annotations.length - 1;
    const position = annotations[index].obj_attr.position as PointType[][];

    if (!position[0]) return;

    if (position[0].length === 1 && annotations[index].id === uuid) {
      const point = position[0][0];
      annotations[index].obj_attr.position = [
        [
          { x: point.x - 5, y: point.y - 5 },
          { x: point.x + 5, y: point.y + 5 },
        ],
      ];
      updateAnnots([...annotations]);
    }

    setRef(null);
    setUuid('');
  }, [annotations, uuid]);

  useEffect(() => {
    const index = annotations.length - 1;

    if (
      annotations[index] &&
      annotations[index].id === uuid &&
      cursorPosition.x &&
      cursorPosition.y
    ) {
      const type = annotations[index].obj_type;
      const position = annotations[index].obj_attr.position as PointType[][];
      const coordinates = parsePositionForBackend(
        type,
        { x: cursorPosition.x, y: cursorPosition.y },
        viewport.height,
        scale
      ) as PointType;

      const lastPosition = position[0].slice(-1)[0];

      if (
        coordinates.x !== lastPosition.x &&
        coordinates.y !== lastPosition.y
      ) {
        position[0].push(coordinates);
        annotations[index].obj_attr.position = position;
        updateAnnots([...annotations]);
      }
    }
  }, [annotations, cursorPosition, uuid]);

  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, handleMouseDown, 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 FreehandTools;
