import * as React from 'react';
import { motion } from 'framer-motion';
import { Properties } from '../Properties/Properties';
import ContainerProperties from '../../Interfaces/IProperties';
import { IContainerModel } from '../../Interfaces/IContainerModel';
import { getDepth, MakeIterator } from '../../utils/itertools';
import { Menu } from '../Menu/Menu';
import { MenuItem } from '../Menu/MenuItem';
import { handleDragLeave, handleDragOver, handleLeftClick, handleOnDrop, handleRightClick } from './MouseEventHandlers';
import { IPoint } from '../../Interfaces/IPoint';

interface IElementsSidebarProps {
  MainContainer: IContainerModel
  isOpen: boolean
  isHistoryOpen: boolean
  SelectedContainer: IContainerModel | null
  OnPropertyChange: (key: string, value: string | number | boolean) => void
  OnPropertiesSubmit: (event: React.FormEvent<HTMLFormElement>, properties: ContainerProperties) => void
  SelectContainer: (container: IContainerModel) => void
  DeleteContainer: (containerid: string) => void
  AddContainer: (index: number, type: string, parent: string) => void
}

function createRows(
  container: IContainerModel,
  props: IElementsSidebarProps,
  containerRows: React.ReactNode[]
): void {
  const depth: number = getDepth(container);
  const key = container.properties.id.toString();
  const text = '|\t'.repeat(depth) + key;
  const selectedClass: string = props.SelectedContainer !== undefined &&
        props.SelectedContainer !== null &&
        props.SelectedContainer.properties.id === container.properties.id
    ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400'
    : 'bg-slate-300/60 hover:bg-slate-300';

  containerRows.push(
    <motion.button
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 1.2 }}
      initial={{ opacity: 0, scale: 0 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{
        duration: 0.150
      }}
      className={
        `w-full border-blue-500 elements-sidebar-row whitespace-pre
          text-left text-sm font-medium transition-all ${selectedClass}`
      }
      id={key}
      key={key}
      onDrop={(event) => handleOnDrop(event, props.MainContainer, props.AddContainer)}
      onDragOver={(event) => handleDragOver(event, props.MainContainer)}
      onDragLeave={(event) => handleDragLeave(event)}
      onClick={() => props.SelectContainer(container)}
    >
      { text }
    </motion.button>
  );
};

export const ElementsSidebar: React.FC<IElementsSidebarProps> = (props: IElementsSidebarProps): JSX.Element => {
  // States
  const [isContextMenuOpen, setIsContextMenuOpen] = React.useState<boolean>(false);
  const [onClickContainerId, setOnClickContainerId] = React.useState<string>('');
  const [contextMenuPosition, setContextMenuPosition] = React.useState<IPoint>({
    x: 0,
    y: 0
  });

  const elementRef = React.useRef<HTMLDivElement>(null);

  // Event listeners
  React.useEffect(() => {
    const onContextMenu = (event: MouseEvent): void => handleRightClick(
      event,
      setIsContextMenuOpen,
      setOnClickContainerId,
      setContextMenuPosition
    );

    const onLeftClick = (): void => handleLeftClick(
      isContextMenuOpen,
      setIsContextMenuOpen,
      setOnClickContainerId
    );

    elementRef.current?.addEventListener(
      'contextmenu',
      onContextMenu
    );

    window.addEventListener(
      'click',
      onLeftClick
    );

    return () => {
      elementRef.current?.removeEventListener(
        'contextmenu',
        onContextMenu
      );

      window.removeEventListener(
        'click',
        onLeftClick
      );
    };
  });

  // Render
  let isOpenClasses = '-right-64';
  if (props.isOpen) {
    isOpenClasses = props.isHistoryOpen
      ? 'right-64'
      : 'right-0';
  }

  const containerRows: React.ReactNode[] = [];

  const it = MakeIterator(props.MainContainer);
  for (const container of it) {
    createRows(
      container,
      props,
      containerRows
    );
  }

  return (
    <div className={`fixed flex flex-col bg-slate-100 text-gray-800 transition-all h-screen w-64 overflow-y-auto z-20 ${isOpenClasses}`}>
      <div className='bg-slate-100 font-bold sidebar-title'>
          Elements
      </div>
      <div ref={elementRef} className='overflow-y-auto overflow-x-hidden text-gray-800 flex-grow'>
        { containerRows }
      </div>
      <Menu
        className='transition-opacity rounded bg-slate-200 py-1 drop-shadow-xl'
        x={contextMenuPosition.x}
        y={contextMenuPosition.y}
        isOpen={isContextMenuOpen}
      >
        <MenuItem className='contextmenu-item' text='Delete' onClick={() => {
          setIsContextMenuOpen(false);
          props.DeleteContainer(onClickContainerId);
        }} />
      </Menu>
      <Properties
        properties={props.SelectedContainer?.properties}
        onChange={props.OnPropertyChange}
        onSubmit={props.OnPropertiesSubmit}
      />
    </div>
  );
};
