import { generateGuid } from '@vev/utils';
import React, { useMemo } from 'react';
import { SilkeBox } from '../silke-box';
import { SilkeDivider } from '../silke-divider';
import { SilkeTextSmall } from '../silke-text';
import type { SilkeListItemType } from './types';
import { groupSilkeListItems, isSilkeListItem } from './utils';
import { SilkeListItem } from './silke-list-item';
import { SilkeSortableItemWrapper } from '../silke-sortable-list/silke-sortable-item-wrapper';

import styles from './silke-list.scss';

type SilkeListProps = {
  items: SilkeListItemType[] | (() => SilkeListItemType[]);
  size?: 's' | 'base';
  gap?: boolean;
  maxHeight?: number;
  /** Enable drag-and-drop reordering of items */
  sortable?: boolean;
  disabled?: boolean;
  onSelect?: (item: SilkeListItemType) => void;
  /** Called with the reordered items array after a drag-and-drop sort */
  onSort?: (items: SilkeListItemType[]) => void;
};

export function SilkeList({ items, size, gap, maxHeight, sortable, disabled, onSelect, onSort }: SilkeListProps) {
  const resolvedItems = typeof items === 'function' ? items() : items;
  const groupedItems = groupSilkeListItems(resolvedItems);
  const hasGroups = groupedItems.some((g) => g.groupLabel);
  const listId = useMemo(() => generateGuid(), []);

  const renderItem = (item: SilkeListItemType, index: number, keyPrefix: string) => {
    const content = (
      <SilkeBox
        tag="li"
        key={`${keyPrefix}-${index}`}
        hPad={item === 'divider' ? 'none' : 'xs'}
      >
        {isSilkeListItem(item) ? (
          <SilkeListItem
            {...item}
            gap={gap}
            size={size}
            maxHeight={maxHeight}
            onSelect={() => onSelect?.(item)}
          />
        ) : item === 'divider' ? (
          <SilkeDivider dark vSpace="xs" />
        ) : (
          React.isValidElement(item) && item
        )}
      </SilkeBox>
    );

    if (sortable && !disabled && onSort && item !== 'divider') {
      return (
        <SilkeSortableItemWrapper
          key={`${keyPrefix}-${index}`}
          listId={listId}
          triggerState="drop"
          items={resolvedItems}
          index={resolvedItems.indexOf(item)}
          onSort={onSort}
        >
          {content}
        </SilkeSortableItemWrapper>
      );
    }

    return content;
  };

  return (
    <SilkeBox
      tag="ul"
      tabIndex={-1}
      column
      className={styles.wrapper}
      vPad="xs"
      hPad="none"
      gap={gap ? 'xxs' : undefined}
      rounded="small"
      style={{ maxHeight: maxHeight ? `${maxHeight}px` : 'none', overflow: 'auto' }}
    >
      {groupedItems.map((group, groupIndex) => (
        <React.Fragment key={group.groupLabel ?? `group-${groupIndex}`}>
          {group.groupLabel && (
            <SilkeBox tag="li" hPad="sm" vPad="s">
              <SilkeTextSmall color="neutral-60" weight="strong">
                {group.groupLabel}
              </SilkeTextSmall>
            </SilkeBox>
          )}
          {group.items.map((item, index) =>
            renderItem(item, index, group.groupLabel ?? `group-${groupIndex}`),
          )}
        </React.Fragment>
      ))}
    </SilkeBox>
  );
}
