import { useEffect, useRef, useState } from 'react';
import type {
  ColumnMeta,
  EditableTableCellProps,
  EditableTableColumnDef,
  TDataWithGroupId,
} from './types';
import { PencilIcon } from '@trail-ui/icons';
import { flexRender } from '@tanstack/react-table';
import EditableSelect from './editable-components/select';
import EditableTextInput from './editable-components/text-input';
import EditableSwitch from './editable-components/switch';
import EditableLink from './editable-components/links';
import EditableCheckBox from './editable-components/checkbox';
import EditableMultiSelect from './editable-components/multiselect';
import { useFocusHandler } from './focus-handler/focus-handler-provider';
import { CellTypes } from './constants';
import { useTableContext } from './table-context/table-context-provider';

export default function EditableTableCell<TData>({
  cell,
  isCellDisabled = () => false,
}: EditableTableCellProps<TData>) {
  const { isCurrentCellFocused: isFocused, focusCurrentCell } = useFocusHandler({
    cellType: CellTypes.dataCell,
    columnIndex: cell.column.getIndex(),
    groupId: null,
    rowId: cell.row.id,
    rowIndex: cell.row.index,
  });

  const { tableRef, doesRowHeaderExist } = useTableContext();
  // Keep union intact and allow undefined
  const columnMeta = cell.column.columnDef.meta as ColumnMeta<TData> | undefined;

  const [isEditing, setIsEditing] = useState(false);
  const cellRef = useRef<HTMLDivElement>(null);

  const isEditable =
    columnMeta &&
    ['link', 'multiselect', 'text', 'date', 'number', 'select', 'switch'].includes(
      columnMeta.type,
    ) &&
    !isCellDisabled(cell.row.original, cell.column.columnDef.id);

  const onKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && isEditable) {
      setIsEditing(true);
      e.preventDefault();
    }
  };

  useEffect(() => {
    if (isFocused && tableRef.current?.contains(document.activeElement)) {
      cellRef.current?.focus();
    }
  }, [isFocused]);

  const onCancel = () => {
    setTimeout(() => {
      cellRef.current?.focus();
    }, 10);

    setIsEditing(false);
  };

  function defaultView() {
    return (
      // eslint-disable-next-line jsx-a11y/no-static-element-interactions
      <div
        ref={cellRef}
        className={`td-content ${
          isEditable
            ? 'editable group flex cursor-pointer items-center justify-between gap-2'
            : 'non-editable'
        } hover:bg-muted relative rounded p-0.5 outline-purple-600 focus:outline focus:outline-2`}
        onClick={() => {
          if (isEditable) {
            setIsEditing(true);
          }
          focusCurrentCell();
        }}
        onKeyDown={onKeyDown}
        // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
        tabIndex={isFocused ? 0 : -1}
      >
        {flexRender(cell.column.columnDef.cell, cell.getContext())}

        {isEditable && <span className="sr-only"> Editable</span>}

        {isEditable && (
          <PencilIcon className="text-muted-foreground h-4 w-4 flex-shrink-0 opacity-0 transition-opacity group-hover:opacity-100 group-focus:opacity-100" />
        )}
      </div>
    );
  }

  function getEditableComponent() {
    switch (columnMeta?.type) {
      case 'link':
        return <EditableLink<TData> cell={cell} />;

      case 'switch':
        return <EditableSwitch<TData> cell={cell} isCellDisabled={isCellDisabled} />;

      case 'checkbox':
        return <EditableCheckBox<TData> cell={cell} />;

      default: {
        if (isEditing) {
          switch (columnMeta?.type) {
            case 'date':
            case 'text':
            case 'number':
              return <EditableTextInput<TData> cell={cell} onCancel={onCancel} />;

            case 'select':
              return <EditableSelect<TData> cell={cell} onCancel={onCancel} />;

            case 'multiselect':
              return <EditableMultiSelect<TData> cell={cell} onCancel={onCancel} />; // TODO: replace with multiselect component later
          }
        }

        return defaultView();
      }
    }
  }

  const Element =
    (cell.column.columnDef as EditableTableColumnDef<TData>).columnType === 'th' ? 'th' : 'td';

  return (
    <Element
      style={{
        minWidth: cell.column.columnDef.size === 100 ? 'auto' : cell.column.columnDef.size,
        maxWidth: cell.column.columnDef.size === 100 ? 'auto' : cell.column.columnDef.size,
        width: cell.column.columnDef.size === 100 ? 'auto' : cell.column.columnDef.size,
      }}
      headers={[
        (cell.column.columnDef.meta as ColumnMeta<TData>)?.type !== 'checkbox' && cell.column.id,
        (cell.row.original as TDataWithGroupId<TData>).editableTableGroupId,
        Element !== 'th' && doesRowHeaderExist && cell.row.id,
      ]
        .filter(Boolean)
        .join(' ')}
      {...(Element === 'th' ? { scope: 'row', id: cell.row.id } : {})}
      className={`${
        cell.row.getIsSelected() ? 'bg-purple-50' : 'bg-neutral-50'
      } border-b border-r border-neutral-200 px-2 py-2 text-left text-sm font-normal text-neutral-900 last:border-r-0`}
    >
      {getEditableComponent()}
    </Element>
  );
}
