import React, { ReactElement, useContext } from 'react';

import { FilterValues } from './types';
import { IconName } from '../../Icon';
import {
  StyledLabeledFilter,
  StyledLabeledFilterContent,
} from './StyledFilters';
import { getDefaultValue, formatValue as defaultFormatValue } from './utils';
import FilterDropdown from './FilterDropdown';
import FiltersContext, {
  useDirtyCheck,
  useFilterState,
} from './FiltersContext';
import SelectedTag from './SelectedTag';

export type FilterProps<T extends FilterValues, K extends keyof T> = {
  children: ({
    value,
    onChange,
  }: {
    onChange: (v: T[K]) => void;
    value: T[K];
  }) => ReactElement;
  clearable?: boolean;
  defaultValue?: T[K];
  filterKey: K;
  formatValue?: (v: T[K]) => string;
  icon?: IconName;
  label?: string;
  noCaret?: boolean;
};

function LabeledFilter({
  label,
  content,
}: {
  content: ReactElement;
  label: string | undefined;
}) {
  return (
    <StyledLabeledFilter>
      {label}
      <StyledLabeledFilterContent>{content}</StyledLabeledFilterContent>
    </StyledLabeledFilter>
  );
}

const Filter = <T extends FilterValues, K extends keyof T>({
  label,
  icon,
  noCaret = false,
  filterKey,
  children,
  defaultValue,
  formatValue = defaultFormatValue,
  clearable = true,
}: FilterProps<T, K>) => {
  const [value, onChange, changeAndSave] = useFilterState<T, K>(filterKey);
  const dirty = useDirtyCheck<T, K>(filterKey);
  const { isGrouped } = useContext(FiltersContext);
  const resetValueIfClearable = clearable
    ? () => changeAndSave(defaultValue ?? (getDefaultValue(value) as T[K]))
    : undefined;
  const content = children({ value, onChange });

  return (
    <>
      {isGrouped ? (
        <LabeledFilter label={label} content={content} />
      ) : (
        <FilterDropdown
          buttonText={label}
          icon={icon}
          content={content}
          dirty={dirty}
          noCaret={noCaret}
          onClearButtonClick={resetValueIfClearable}
        />
      )}
      {dirty && (
        <SelectedTag
          label={label}
          value={formatValue(value)}
          onRemove={resetValueIfClearable}
        />
      )}
    </>
  );
};

export default Filter;
