import React, { useCallback } from 'react';
import { createPortal } from 'react-dom';
import { observer } from 'mobx-react-lite';
import type { FiltersMap } from '@wix/bex-core';
import { DropdownLayout, listItemActionBuilder } from '@wix/design-system';
import {
  DeleteSmall,
  AddSmall,
  DuplicateSmall,
} from '@wix/wix-ui-icons-common';
import type { EditableTableState, Cell } from '../../state/EditableTable';

export interface EditableTableContextMenuProps<T, F extends FiltersMap> {
  state: EditableTableState<T, F>;
  position: { x: number; y: number } | null;
  cell: Cell | null;
  menuRef: React.Ref<HTMLDivElement>;
  onClose: () => void;
}

const MENU_WIDTH = 230;
const ITEM_HEIGHT = 36;
const DIVIDER_HEIGHT = 9;
const PADDING = 16;
const OFFSET_X = 4;
const OFFSET_Y = 4;

function _EditableTableContextMenu<T, F extends FiltersMap>({
  state,
  position,
  cell,
  menuRef,
  onClose,
}: EditableTableContextMenuProps<T, F>) {
  const {
    cellInteraction,
    clipboard,
    addItemDisabled,
    updateItemDisabled,
    removeItemDisabled,
  } = state;

  const handleCopy = useCallback(async () => {
    const tsv = clipboard.copy();
    try {
      await navigator.clipboard.writeText(tsv);
    } catch {}
    onClose();
  }, [clipboard, onClose]);

  const handleCut = useCallback(async () => {
    const tsv = clipboard.cut();
    try {
      await navigator.clipboard.writeText(tsv);
    } catch {}
    onClose();
  }, [clipboard, onClose]);

  const handlePaste = useCallback(async () => {
    if (!cellInteraction.focusedCell) {
      return;
    }
    try {
      const rawData = await navigator.clipboard.readText();
      if (!rawData) {
        onClose();
        return;
      }
      clipboard.paste(rawData);
    } catch {}
    onClose();
  }, [cellInteraction, clipboard, onClose]);

  const handleClear = useCallback(() => {
    state.clearCells(cellInteraction.selectedCellsList);
    onClose();
  }, [state, cellInteraction, onClose]);

  if (!position || !cell) {
    return null;
  }

  const selectedCells = cellInteraction.selectedCellsList;
  const selectedCount = selectedCells.length;
  const selectedRowKeys = [...new Set(selectedCells.map((c) => c.rowKey))];
  const hasMultipleRows = selectedRowKeys.length > 1;

  const options = [];

  options.push(
    listItemActionBuilder({
      id: 'copy',
      title: `Copy`,
      disabled: selectedCount === 0,
    }),
    listItemActionBuilder({
      id: 'cut',
      title: `Cut`,
      disabled: selectedCount === 0 || !!updateItemDisabled,
    }),
    listItemActionBuilder({
      id: 'paste',
      title: `Paste`,
      disabled: !!updateItemDisabled,
    }),
    listItemActionBuilder({
      id: 'clear',
      title: selectedCount > 1 ? `Clear ${selectedCount} Cells` : 'Clear Cell',
      disabled: selectedCount === 0 || !!updateItemDisabled,
    }),
  );

  const hasRowOps = !addItemDisabled || !removeItemDisabled;
  if (hasRowOps) {
    options.push({ id: 'divider-1', value: '-' });
  }

  if (!addItemDisabled) {
    options.push(
      listItemActionBuilder({
        id: 'add-above',
        title: 'Add Row Above',
        prefixIcon: <AddSmall />,
      }),
      listItemActionBuilder({
        id: 'add-below',
        title: 'Add Row Below',
        prefixIcon: <AddSmall />,
      }),
      listItemActionBuilder({
        id: 'duplicate',
        title: 'Duplicate Row',
        prefixIcon: <DuplicateSmall />,
      }),
    );
  }

  if (!removeItemDisabled) {
    if (!addItemDisabled) {
      options.push({ id: 'divider-2', value: '-' });
    }
    options.push(
      listItemActionBuilder({
        id: 'delete',
        title: hasMultipleRows
          ? `Delete ${selectedRowKeys.length} Rows`
          : 'Delete Row',
        prefixIcon: <DeleteSmall />,
        skin: 'destructive',
      }),
    );
  }

  const handleSelect = (option: { id: string | number }) => {
    switch (option.id) {
      case 'copy':
        handleCopy();
        break;
      case 'cut':
        handleCut();
        break;
      case 'paste':
        handlePaste();
        break;
      case 'clear':
        handleClear();
        break;
      case 'add-above': {
        const rowIdx = state.keyedItems.findIndex(
          (ki) => ki.key === cell.rowKey,
        );
        const prevKey =
          rowIdx > 0 ? state.keyedItems[rowIdx - 1].key : undefined;
        state.addItem(prevKey);
        onClose();
        break;
      }
      case 'add-below':
        state.addItem(cell.rowKey);
        onClose();
        break;
      case 'duplicate':
        state.duplicateItem(cell.rowKey);
        onClose();
        break;
      case 'delete':
        state.confirmDeleteItems(
          hasMultipleRows ? selectedRowKeys : [cell.rowKey],
        );
        onClose();
        break;
    }
  };

  const dividerCount = options.filter(
    (o) => 'value' in o && o.value === '-',
  ).length;
  const itemCount = options.length - dividerCount;
  const estimatedHeight =
    itemCount * ITEM_HEIGHT + dividerCount * DIVIDER_HEIGHT + PADDING;

  const x =
    position.x + OFFSET_X + MENU_WIDTH > window.innerWidth
      ? position.x - MENU_WIDTH
      : position.x + OFFSET_X;
  const y =
    position.y + OFFSET_Y + estimatedHeight > window.innerHeight
      ? Math.max(4, position.y - estimatedHeight)
      : position.y + OFFSET_Y;

  return createPortal(
    <div
      ref={menuRef}
      style={{
        position: 'fixed',
        left: x,
        top: y,
        zIndex: 1000,
        width: MENU_WIDTH,
      }}
      onMouseDown={(e) => e.preventDefault()}
    >
      <DropdownLayout
        dataHook="editable-table-context-menu"
        visible
        inContainer
        options={options}
        onSelect={handleSelect}
        onClose={onClose}
        maxHeightPixels={400}
      />
    </div>,
    document.body,
  );
}

export const EditableTableContextMenu = observer(_EditableTableContextMenu);
