// @flow
import React, { useCallback, useState, useMemo } from 'react';
import styled from 'styled-components';
import { v4 } from 'uuid';
import { remove, concat } from 'lodash';
import type { SelectorProps } from './selector.proptypes';
import { getPaletteColor } from '../../../mixins/branding';
import { getSpacingRules } from '../../../mixins/spacing';
import { getStackeeRules } from '../../../mixins/stackee';
import { FieldLabel } from '../../typography/field-label';
import { SelectorContextProvider } from './selector-context';
import { HideAccessibly } from '../../../primitives/hide-accessibly';
import { useDeprecationWarning } from '../../../utils/use-deprecation-warning.hook';

const SelectorContainer = styled.div`
  &&& {
    ${getSpacingRules}
  }
  ${getStackeeRules};
`;

// TODO: why is this not a FormList?
const ListContainer = styled.div`
  && {
    border: 1px solid ${getPaletteColor('greyscale-light')};
    border-radius: 6px;
  }

  & > *:first-child {
    border-radius: 6px 6px 0 0;
  }

  & > *:only-child {
    border-radius: 6px;
  }

  && > * {
    border-bottom: 1px solid ${getPaletteColor('greyscale-light')};
  }

  && > *:last-child {
    border-bottom: 0;
    border-radius: 0 0 6px 6px;
  }
`;

export const SizeContext = React.createContext<
  $PropertyType<SelectorProps, 'size'>,
>('md');

export const Selector = ({
  label,
  hideLabel = false,
  children,
  size,
  stateful,
  name,
  onChange,
  type = 'radio',
  spacing,
  grow,
  shrink,
  basis,
  hasBorder = true,
  className,
  'data-qa': dataQa,
  'data-cy': dataCy,
  id,
  ...props
}: SelectorProps) => {
  useDeprecationWarning('Selector', undefined, 'ListSelector');

  const [managedValue, setManagedValue] = useState();

  const handleChange = useCallback(
    (event) => {
      if (!stateful) {
        onChange(event.target.value);
        return;
      }

      let newValue = event.target.value;

      if (type === 'checkbox' && Array.isArray(managedValue)) {
        if (managedValue.includes(newValue)) {
          // Removing
          newValue = remove(managedValue, (v) => v !== newValue);
        } else {
          // Adding
          newValue = concat(managedValue, newValue);
        }
      }

      setManagedValue(newValue);
      onChange(newValue);
    },
    [managedValue, onChange, stateful, type],
  );

  const selectorId = useMemo(() => `selector-${v4()}`, []);

  return (
    <SelectorContainer
      {...{ spacing, grow, shrink, basis }}
      className={className}
      data-cy={dataCy}
      data-qa={dataQa}
      id={id}
      {...props}
    >
      <SizeContext.Provider value={size}>
        {hideLabel ? (
          <HideAccessibly>
            <FieldLabel htmlFor={selectorId} spacing={['pt0', 'pb1']}>
              {label}
            </FieldLabel>
          </HideAccessibly>
        ) : (
          <FieldLabel htmlFor={selectorId} spacing={['pt0', 'pb1']}>
            {label}
          </FieldLabel>
        )}
        <SelectorContextProvider
          value={{ stateful, name, onChange: handleChange, managedValue, type }}
        >
          {hasBorder ? (
            <ListContainer id={selectorId}>{children}</ListContainer>
          ) : (
            children
          )}
        </SelectorContextProvider>
      </SizeContext.Provider>
    </SelectorContainer>
  );
};

Selector.displayName = 'Selector';
