import {
  findNodePath,
  focusEditor,
  insertNodes,
  setNodes,
  TElement,
} from '@udecode/plate-common';
import { useEditorRef, useElement } from '@udecode/plate-core';
import { ELEMENT_PARAGRAPH } from '@udecode/plate-paragraph';
import { Path } from 'slate';

import { ELEMENT_LAYOUT, ELEMENT_LAYOUT_CHILD } from './createLayoutPlugin';

export interface TLayoutChildElement extends TElement {
  id?: string;
  type: 'layout_child';
  width: string;
}

export interface TLayoutBlockElement extends TElement {
  id?: string;
  type: 'layout';
  children: TLayoutChildElement[];
}

export const useLayoutState = () => {
  const editor = useEditorRef();

  const layoutElement = useElement<TLayoutBlockElement>(ELEMENT_LAYOUT);
  const element = useElement<TLayoutChildElement>(ELEMENT_LAYOUT_CHILD);

  const halvePercentage = (percentage: string) => {
    const number = Number.parseInt(percentage);
    const halvedNumber = Math.floor(number / 2);
    const halvedPercentage = halvedNumber + '%';
    return halvedPercentage;
  };

  const insertChild = (path: Path) => {
    if (!path) return;

    const curWidth = halvePercentage(element.width);

    if (Number.parseInt(curWidth) < 10) return;

    setCurrentChildWidth(curWidth);

    insertNodes(
      editor,
      {
        width: curWidth,
        type: ELEMENT_LAYOUT_CHILD,
        children: [{ type: ELEMENT_PARAGRAPH, children: [{ text: '' }] }],
      },
      { at: path }
    );

    focusEditor(editor, path);
  };

  const insertLeft = () => {
    const path = findNodePath(editor, element);
    if (!path) return;

    const targetPath = [path[0], path[1]];
    insertChild(targetPath);
  };

  const insertRight = () => {
    const path = findNodePath(editor, element);
    if (!path) return;

    const targetPath = [path[0], path[1] + 1];
    insertChild(targetPath);
  };

  const setCurrentChildWidth = (value: string) => {
    const path = findNodePath(editor, element);

    if (isInvalidValue(value)) return false;

    setNodes(
      editor,
      {
        width: value,
      },
      { at: path }
    );

    return true;
  };

  const setDynamicChildWidth = (value: string) => {
    if (isInvalidValue(value)) return false;

    const path = findNodePath(editor, element);

    const updateValue = Number.parseInt(value);
    const differenceValue = Number.parseInt(element.width) - updateValue;
    const offsetNode = layoutElement.children
      .filter((v) => v.id !== element.id)
      .reduce(
        (prev, current) => {
          return Number.parseInt(prev.width) > Number.parseInt(current.width)
            ? prev
            : current;
        },
        { ...element, width: '0%' }
      );

    if (!offsetNode) return;
    const offsetNodePath = findNodePath(editor, offsetNode);
    const offsetNodeWidth = `${
      Number.parseInt(offsetNode.width) + differenceValue
    }%`;
    if (isInvalidValue(offsetNodeWidth)) return false;

    setNodes(editor, { width: value }, { at: path });
    setNodes(editor, { width: offsetNodeWidth }, { at: offsetNodePath });
    return true;
  };

  const isInvalidValue = (value: string): boolean => {
    if (!value.endsWith('%')) return true;
    const numValue = Number(value.replace('%', ''));
    return numValue > 100 || numValue < 10;
  };

  return {
    element,
    layoutElement,
    insertRight,
    insertLeft,
    setDynamicChildWidth,
  };
};
