import React from 'react';
import { SilkeBox } from '../silke-box';
import { SilkeIcon } from '../silke-icon';
import styles from './silke-nested-sortable-list.scss';
import {
  getIndentLevel,
  hasState,
  Item,
  ItemState,
  RenderFunction,
  SilkeSortableIconComponent,
} from './silke-nested-sortable-utils';

type SilkeNestedSortableItemProps<T> = {
  item: Item<T>;
  state: number;
  index: number;
  className?: string;
  replaceIcon?: SilkeSortableIconComponent<T>;
  children: RenderFunction<T>;
  onMouseDown?: (e: React.MouseEvent<HTMLDivElement>, item: Item<T>) => void;
  onDoubleClick?: (e: React.MouseEvent<HTMLDivElement>, item: Item<T>) => void;
  onCollapseToggle?: (item: Item<T>) => void;
  onMouseEnter?: (e: React.MouseEvent, item: Item<T>) => void;
  onMouseLeave?: (e: React.MouseEvent, item: Item<T>) => void;
};

export function SilkeNestedSortableItem<T>({
  item,
  index,
  state,
  children,
  replaceIcon,
  className,
  onCollapseToggle,
  onMouseDown,
  onDoubleClick,
  onMouseEnter,
  onMouseLeave,
}: SilkeNestedSortableItemProps<T>) {
  let cl = styles.item;
  const hasChildren = hasState(state, ItemState.canHaveChildren);
  const indent = getIndentLevel(state);
  const isSelected = hasState(state, ItemState.selected);
  const isChildOfSelected = hasState(state, ItemState.childOfSelected);

  if (isSelected) cl += ' ' + styles.selected;
  if (isChildOfSelected) cl += ' ' + styles.childOfSelected;
  if (hasState(state, ItemState.roundTop)) cl += ' ' + styles.roundTop;
  if (hasState(state, ItemState.roundBottom)) cl += ' ' + styles.roundBottom;
  if (hasState(state, ItemState.childOfSelected)) cl += ' ' + styles.childOfSelected;

  if (hasState(state, ItemState.placeAfter)) cl += ' ' + styles.placeAfter;
  if (hasState(state, ItemState.placeBefore)) cl += ' ' + styles.placeBefore;
  if (hasState(state, ItemState.placeInside)) cl += ' ' + styles.placeInside;
  if (hasState(state, ItemState.placementInvalid)) cl += ' ' + styles.placementInvalid;

  if (hasChildren) cl += ' ' + styles.hasChildren;
  if (item.disabled) cl += ' ' + styles.disabled;
  if (indent) cl += ' ' + styles[`indent${indent}`];

  if (item.className) cl += ' ' + item.className;
  if (className) cl += ' ' + className;

  const content = children({ ...item, expanded: !hasState(state, ItemState.collapsed) }, index);
  if (!content) return null;

  const shouldShowExpandIcon =
    item.showExpandIcon !== undefined ? item.showExpandIcon : (item.children?.length || 0) > 0;

  const IconComponent = typeof item.replaceIcon === 'function' ? item.replaceIcon : replaceIcon;

  const handleIconClick = (e: React.MouseEvent<HTMLDivElement>) => {
    if (hasChildren) e.stopPropagation();
    onCollapseToggle?.(item);
  };

  return (
    <div
      className={cl}
      style={item.style}
      tabIndex={item.disabled ? undefined : 0}
      data-selected={isSelected || null}
      data-child-of-selected={isChildOfSelected || null}
      onMouseDown={!item.disabled && onMouseDown ? (e) => onMouseDown(e, item) : undefined}
      onDoubleClick={!item.disabled && onDoubleClick ? (e) => onDoubleClick(e, item) : undefined}
      onMouseEnter={
        onMouseEnter && !item.disabled ? (e: React.MouseEvent) => onMouseEnter(e, item) : undefined
      }
      onMouseLeave={
        onMouseLeave && !item.disabled ? (e: React.MouseEvent) => onMouseLeave(e, item) : undefined
      }
    >
      {IconComponent ? (
        <IconComponent
          collapsed={hasState(state, ItemState.collapsed)}
          selected={isSelected}
          hasChildren={hasChildren && shouldShowExpandIcon}
          item={item}
          onMouseDown={handleIconClick}
        />
      ) : (
        onCollapseToggle &&
        !item.disableCollapse && (
          <SilkeBox
            className={styles.expand}
            tabIndex={1}
            align="center"
            height="base"
            width="xs"
            hAlign="center"
            vAlign="center"
            onMouseDown={handleIconClick}
            style={{ marginLeft: `var(--space-xs)` }}
          >
            {!shouldShowExpandIcon ? null : (
              <SilkeIcon
                color={isSelected ? 'neutral-100' : 'surface-4'}
                icon={
                  typeof item.replaceIcon === 'object'
                    ? item.replaceIcon.icon
                    : hasState(state, ItemState.collapsed)
                      ? 'caret.right'
                      : 'caret.down'
                }
                style={
                  typeof item.replaceIcon === 'object'
                    ? {
                        color: item.replaceIcon.color,
                      }
                    : undefined
                }
              />
            )}
          </SilkeBox>
        )
      )}
      {content}
    </div>
  );
}
