import { ANNOTATION_TYPE } from '../constants';
import { parseAnnotationObject, appendUserIdAndDate } from './annotation';

type GetMarkupWithSelectionFunc = ({
  color,
  type,
  opacity,
  scale,
}: {
  color: string;
  type: string;
  opacity: number;
  scale: number;
  textLayer: HTMLElement;
}) => AnnotationType | null;

export const getMarkupWithSelection: GetMarkupWithSelectionFunc = ({
  color,
  type,
  opacity,
  scale,
  textLayer,
}) => {
  const selection: Selection | null = document.getSelection();

  if (!selection || selection.isCollapsed) return null;
  const {
    startContainer,
    startOffset,
    endContainer,
    endOffset,
  } = selection.getRangeAt(0);
  const startElement = startContainer.parentNode as HTMLElement;
  const endElement = endContainer.parentNode as HTMLElement;
  const startPage = startElement?.parentNode?.parentNode as HTMLElement;
  const startPageNum = parseInt(
    startPage.getAttribute('data-page-num') as string,
    10
  );

  const pageHeight = startPage.offsetHeight;

  const startCloneEle = startElement.cloneNode(true) as HTMLElement;
  const endCloneEle = endElement.cloneNode(true) as HTMLElement;

  const startText = startElement.innerText.substring(0, startOffset);
  const endText = endElement.innerText.substring(endOffset);

  startCloneEle.innerText = startText;
  endCloneEle.innerText = endText;
  textLayer.appendChild(startCloneEle);
  textLayer.appendChild(endCloneEle);

  const startExtraWidth = startCloneEle.getBoundingClientRect().width;
  const endExtraWidth = endCloneEle.getBoundingClientRect().width;

  textLayer.removeChild(startCloneEle);
  textLayer.removeChild(endCloneEle);

  const info: AnnotationType = {
    obj_type: '',
    obj_attr: {
      page: 0,
      bdcolor: '',
      position: [],
      transparency: 0,
    },
  };
  const position: PositionType[] = [];

  const startRect = startElement.getBoundingClientRect();
  const endRect = endElement.getBoundingClientRect();

  // left to right and up to down select
  let startX = startElement.offsetLeft + startExtraWidth;
  let startY = startElement.offsetTop;
  let endX = endElement.offsetLeft + endRect.width - endExtraWidth;
  let endY = endElement.offsetTop + endRect.height;

  if (startX > endX && startY >= endY) {
    // right to left and down to up select
    startX = endElement.offsetLeft + startExtraWidth;
    startY = endElement.offsetTop;
    endX = startElement.offsetLeft + startRect.width - endExtraWidth;
    endY = startElement.offsetTop + startRect.height;
  }
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
  // @ts-ignore
  const textElements = [...textLayer.childNodes];
  let inRange = false;

  textElements.forEach((ele: HTMLElement) => {
    const { height, width } = ele.getBoundingClientRect();
    const { offsetTop, offsetLeft } = ele;

    const top = offsetTop;
    const left = offsetLeft;
    const right = offsetLeft + width;
    const bottom = offsetTop + height;
    const coords = {
      top,
      bottom,
      left,
      right,
    };

    if (startElement === ele && endElement === ele) {
      // in same element
      coords.left = startX;
      coords.right = endX;
      position.push(coords);
    } else if (startElement === ele) {
      // in start element
      coords.left = startX;
      position.push(coords);
      inRange = true;
    } else if (endElement === ele) {
      // in end element
      coords.right = endX;
      position.push(coords);
      inRange = false;
    } else if (inRange) {
      // middle element
      position.push(coords);
    }
  });

  for (let i = 1; i < position.length; i += 1) {
    if (
      position[i].top >= position[i - 1].top - 4 &&
      position[i].bottom <= position[i - 1].bottom + 4
    ) {
      position[i - 1].right = position[i].left;
    }
  }

  info.obj_type = ANNOTATION_TYPE[type];
  info.obj_attr = {
    page: startPageNum,
    bdcolor: color,
    position,
    transparency: opacity,
  };

  return appendUserIdAndDate(parseAnnotationObject(info, pageHeight, scale));
};

export default getMarkupWithSelection;
