/* eslint-disable jsx-a11y/no-static-element-interactions */
import { flexRender, type Header, type Table } from '@tanstack/react-table';
import { ArrowDownIcon, ArrowUpIcon, CaretUpDownIcon } from '@trail-ui/icons';
import type { EditableTableColumnDef } from './types';
import { useFocusHandler } from './focus-handler/focus-handler-provider';
import { useTableContext } from './table-context/table-context-provider';
import { useEffect, useRef } from 'react';
import { CellTypes } from './constants';
import { replaceSpacesWithHyphens } from '../_utils/utils';

export interface EditableTableHeaderProps<TData> {
  table: Table<TData>;
  tableName: string;
  selectAllCheckBoxName?: string;
}

export default function EditableTableHeader<TData>({
  table,
  selectAllCheckBoxName,
  tableName,
}: EditableTableHeaderProps<TData>) {
  return (
    <thead className="sticky top-0 z-10 after:absolute after:bottom-0 after:w-full after:border-t after:border-t-neutral-200">
      {table.getHeaderGroups().map((group) => (
        <tr key={group.id}>
          {group.headers.map((header) => (
            <HeaderCell
              key={header.id}
              header={header}
              tableName={tableName}
              selectAllCheckBoxName={selectAllCheckBoxName}
            />
          ))}
        </tr>
      ))}
    </thead>
  );
}

function HeaderCell<TData>({
  header,
  selectAllCheckBoxName,
  tableName,
}: {
  header: Header<TData, unknown>;
  selectAllCheckBoxName?: string;
  tableName: string;
}) {
  const cellRef = useRef<HTMLDivElement>(null);

  const { table, tableRef } = useTableContext();
  const { isCurrentCellFocused, focusCurrentCell } = useFocusHandler({
    cellType: CellTypes.headerCell,
    columnIndex: header.column.getIndex(),
    groupId: null,
    rowId: null,
    rowIndex: -1,
  });

  const canSort = header.column.getCanSort();
  const isCheckbox =
    (header.column.columnDef as EditableTableColumnDef<TData>).meta?.type === 'checkbox';

  const tabIndex = tableRef.current?.contains(document.activeElement)
    ? isCurrentCellFocused
      ? 0
      : -1
    : 0 === header.column.getIndex()
      ? 0
      : -1;

  const classes = 'border-b border-r bg-neutral-100 p-2 text-sm font-normal last:border-r-0';

  function onFocusChange() {
    if (!isCurrentCellFocused && 0 === header.column.getIndex()) {
      focusCurrentCell();
    }
  }

  /** ---- Sorting Icon Renderer ---- */
  const renderSortIcon = (sorted: false | 'asc' | 'desc') => {
    switch (sorted) {
      case 'asc':
        return <ArrowUpIcon className="h-4 w-4 text-purple-600" />;
      case 'desc':
        return <ArrowDownIcon className="h-4 w-4 text-purple-600" />;
      default:
        return <CaretUpDownIcon className="h-4 w-4 text-neutral-600" />;
    }
  };

  /** ---- Checkbox Handler ---- */
  const toggleCheckbox = (elem: HTMLElement) => {
    const checkbox = elem.querySelector('input[type="checkbox"]') as HTMLInputElement | null;
    checkbox?.click();
  };

  useEffect(() => {
    if (isCurrentCellFocused) {
      cellRef.current?.focus();
    }
  }, [isCurrentCellFocused]);

  if (isCheckbox) {
    return (
      <td
        key={header.id}
        id={header.column.id}
        style={{
          minWidth: header.column.columnDef.size === 100 ? 'auto' : header.column.columnDef.size,
          maxWidth: header.column.columnDef.size === 100 ? 'auto' : header.column.columnDef.size,
          width: header.column.columnDef.size === 100 ? 'auto' : header.column.columnDef.size,
        }}
        className={`${classes} text-center`}
      >
        <div
          id={`${replaceSpacesWithHyphens(tableName)}-${header.column.getIndex()}`}
          ref={cellRef}
          // biome-ignore lint/a11y/useSemanticElements: <explanation>
          role="checkbox"
          aria-label={selectAllCheckBoxName ?? `Select all ${tableName}`}
          aria-checked={
            table.getIsAllRowsSelected()
              ? 'true'
              : table.getIsSomeRowsSelected()
                ? 'mixed'
                : 'false'
          }
          className="th-content flex h-6 w-6 cursor-pointer items-center justify-center outline-purple-600"
          onClick={(e) => toggleCheckbox(e.currentTarget)}
          onKeyDown={(e) => {
            if (e.key === 'Enter' || e.key === ' ') {
              e.preventDefault();
              toggleCheckbox(e.currentTarget);
            }
          }}
          tabIndex={tabIndex}
          onFocus={onFocusChange}
        >
          {flexRender(header.column.columnDef.header, header.getContext())}
        </div>
      </td>
    );
  }

  return (
    <th
      key={header.id}
      id={header.column.id}
      scope="col"
      className={`${classes} text-left`}
      style={{
        minWidth: header.column.columnDef.size === 100 ? 'auto' : header.column.columnDef.size,
        width: header.column.columnDef.size === 100 ? 'auto' : header.column.columnDef.size,
      }}
      {...(canSort && {
        'aria-sort':
          header.column.getIsSorted() === 'asc'
            ? 'ascending'
            : header.column.getIsSorted() === 'desc'
              ? 'descending'
              : 'none',
      })}
    >
      <div
        ref={cellRef}
        className={`th-content flex items-center justify-between rounded px-2 text-sm font-semibold outline-purple-600 focus:outline focus:outline-2 ${
          canSort ? 'cursor-pointer select-none' : ''
        }`}
        onClick={() => {
          if (canSort) {
            header.column.toggleSorting();
          }
          focusCurrentCell();
        }}
        onKeyDown={(e) => {
          if (e.key === ' ' && canSort) {
            e.preventDefault();
            header.column.toggleSorting();
          }
        }}
        tabIndex={tabIndex}
        onFocus={onFocusChange}
      >
        <span id={`${replaceSpacesWithHyphens(tableName)}-${header.column.getIndex()}`}>
          {flexRender(header.column.columnDef.header, header.getContext())}
        </span>
        {canSort && (
          <>
            <span className="sr-only">Sortable</span>
            {renderSortIcon(header.column.getIsSorted())}
          </>
        )}
      </div>
    </th>
  );
}
