import React, { ReactElement, useState, FormEvent, CSSProperties } from "react";
import classnames from "classnames";
import { Box } from "../Box";
import { CheckboxProps } from "../Checkbox";
import { FilterDropdown } from "./FilterDropdown";
import TableContext, { SORT_DIRECTION } from "./TableContext";
import { bem } from "../../utilities/bem";
import { Icon, ICON_TYPE } from "../Icon";
import isUndefined from "../../utilities/isUndefined";

const cn = "TableHeaderCell";

// Typescript can't actually enforce children having certain props,
// so this interface doesn't work. TODO: Handle this some other way
interface FilterProps extends CheckboxProps {
  label: string;
}

export interface TableHeaderCellProps
  extends React.HTMLProps<HTMLTableHeaderCellElement> {
  /**
   * This will set the width for the entire column. Any valid CSS value for the `width`
   * property is acceptable (e.g. "100px", "20%", etc.)
   */
  columnWidth?: string;

  /**
   * This will set a minWidth for the entire column. Any valid CSS value for the `min-width`
   * property is acceptable (e.g. "100px", "20%", etc.)
   */
  minColumnWidth?: string;

  /**
   * If true, this changes the filter icon green to indicate a filter within is applied
   */
  filterApplied?: boolean;

  /**
   * Hides the search input and "Select All"/"Clear links in the filter dropdown"
   */
  hideFilterSearch?: boolean;

  /**
   * Required with the `sortable` prop to enable sorting
   */
  id?: string;

  /**
   * Callback when the "Clear" link is clicked in the filter dropdown
   */
  onClearFilters?: () => void;

  /**
   * Callback when input in the filter dropdown is changed
   */
  onSearchInputChange?: (value: string) => void;

  /**
   * Callback when the "Select All" link is clicked in the filter dropdown
   */
  onSelectAllFilters?: () => void;

  /**
   * Removes top and bottom padding within the HeaderCell
   */
  removeVerticalPadding?: boolean;

  /**
   * Value provided to the input in the filter dropdown
   */
  searchInputValue?: string;

  /**
   * Shrinks column to minimum width without breaking words.
   */
  shrinkToContent?: boolean;

  /**
   * Enables sorting on the column. Must also include an `id` prop to work properly.
   */
  sortable?: boolean;

  /**
   * Enables column filtering
   */
  filterOptions?: ReactElement<FilterProps>[];

  /**
   * Specify a custom filter control, e.g. DatePicker
   */
  filterControl?: ReactElement;
}

const TableHeaderCell = ({
  children,
  className,
  id,
  shrinkToContent = false,
  sortable = true,
  filterOptions: filterOptionsProp,
  onSelectAllFilters,
  onClearFilters,
  hideFilterSearch = false,
  filterApplied = false,
  searchInputValue = "",
  onSearchInputChange,
  columnWidth,
  minColumnWidth,
  removeVerticalPadding = false,
  filterControl,
  style,
  ...rest
}: TableHeaderCellProps) => {
  const [filterDropDownOpen, setFilterDropdownOpen] = useState<boolean>(false);
  const filterOptions = filterOptionsProp;

  return (
    <TableContext.Consumer>
      {({ handleSort, sortColumnId, sortDirection, renderInModal }) => {
        const classes = classnames(
          bem(cn),
          shrinkToContent && bem(cn, { m: "shrinkToContent" }),
          removeVerticalPadding && bem(cn, { m: "removeVerticalPadding" }),
          className,
        );

        const handleSortClick = () => {
          if (sortable && id && handleSort) {
            handleSort(id);
          }
        };

        const handleFilterInputChange = (e: FormEvent<HTMLInputElement>) => {
          const { value } = e.target as HTMLInputElement;
          if (!isUndefined(onSearchInputChange)) {
            onSearchInputChange(value);
          }
        };

        const handleFilterSelectAll = () => {
          if (!isUndefined(onSelectAllFilters)) {
            onSelectAllFilters();
          }
        };

        const handleFilterClear = () => {
          if (!isUndefined(onClearFilters)) {
            onClearFilters();
          }
        };

        let sortIcon = ICON_TYPE.SORT;
        let sortActive = false;
        if (sortable && id && sortColumnId === id) {
          sortActive = true;
          sortIcon =
            sortDirection === SORT_DIRECTION.ASC
              ? ICON_TYPE.SORT_UP
              : ICON_TYPE.SORT_DOWN;
        }

        const computedStyle: CSSProperties = { ...style };
        if (columnWidth) {
          computedStyle.width = columnWidth;
        }

        if (minColumnWidth) {
          computedStyle.minWidth = minColumnWidth;
        }

        return (
          <th className={classes} style={computedStyle} {...rest}>
            <Box className={bem(cn, { e: "InnerWrapper" })}>
              <Box className={bem(cn, { e: "ChildrenWrapper" })}>
                {children}
              </Box>
              {(filterOptions || filterControl || sortable) && (
                <Box
                  className={classnames(bem(cn, { e: "iconButtonWrapper" }))}
                >
                  {(filterOptions || filterControl) && (
                    <FilterDropdown
                      isVisible={filterDropDownOpen}
                      onSetVisible={setFilterDropdownOpen}
                      hideFilterSearch={hideFilterSearch}
                      filterApplied={filterApplied}
                      searchInputValue={searchInputValue}
                      onFilterInputChange={handleFilterInputChange}
                      onFilterSelectAll={handleFilterSelectAll}
                      onFilterClear={handleFilterClear}
                      filterOptions={filterOptions}
                      filterControl={filterControl}
                      className={classnames(
                        filterControl && "hasControls",
                        renderInModal ? "z-toast" : null,
                      )}
                    />
                  )}
                  {sortable && (
                    <Box
                      as="button"
                      className={classnames(bem(cn, { e: "iconButton" }))}
                      onClick={handleSortClick}
                    >
                      <Icon
                        icon={sortIcon}
                        className={classnames(bem(cn, { e: "sortIcon" }), {
                          isActive: sortActive,
                        })}
                      />
                    </Box>
                  )}
                </Box>
              )}
            </Box>
          </th>
        );
      }}
    </TableContext.Consumer>
  );
};

export default TableHeaderCell;
