import React from 'react';
import { Animated, Image } from 'react-native';
import { ThemeProvider } from 'styled-components/native';

import Theme from '../../theme';

import Box from '../../atoms/Box';
import Touchable from '../../atoms/Touchable';
import Scrollable from '../../atoms/Scrollable';
import Text from '../../atoms/Text';

export const selectBoxID = 'select-box-id';
export const selectBoxIconID = 'select-box-icon';
export const selectBoxSelectedValueText = 'select-box-selected-value-text';

export const selectBoxOptionsContainer = 'select-box-options-container';
export const selectBoxOption = 'select-box-option';
export const selectBoxOptionIconID = 'select-box-option-icon';
export const selectBoxOptionTextID = 'select-box-option-text';
export const selectBoxOptionCheckID = 'select-box-option-check';

type Icon = string|((props: any) => React.ReactElement);

type OptionsHasDuplicates = {value: string}[];
function optionsHasDuplicates(opts: OptionsHasDuplicates) {
  const optionValues = opts.map(({ value }) => value);
  return optionValues.length !== [...new Set(optionValues)].length;
}

interface SelectIcon { Icon?: Icon; testID?: string; }
function SelectIcon({ Icon, ...props }: SelectIcon) {
  if (Icon) {
    if (typeof Icon === 'string') {
      const src = { uri: Icon };
      // eslint-disable-next-line jsx-a11y/alt-text
      return <Image source={src} {...props} />;
    }
    return <Icon {...props} />;
  }

  return null;
}

interface OPTION {
  value: string;
  label: string;
  Icon?: Icon
}

const SELECT_HEIGHT = 60;

interface SelectBoxProps {
  placeholder: string;
  value: string;
  options: OPTION[];
  onSelect: (selectedValue: string) => void;
  Icon?: Icon;
  iconPosition?: 'right'|'left';
  disabled?: boolean
}
function SelectBox({
  placeholder,
  value,
  options,
  onSelect,
  iconPosition = 'right',
  Icon,
  disabled = false
}: SelectBoxProps) {
  if (optionsHasDuplicates(options)) {
    // eslint-disable-next-line no-console
    console.warn('The options you have provided have multiples of the same `value`, this will cause rendering issues. Make sure each option has a unique `value` key.');
  }

  const [open, setOpen] = React.useState(false);
  const [highlighted, setHighlighted] = React.useState('');
  const [chevronPos] = React.useState(new Animated.Value(0));

  React.useEffect(() => {
    Animated
      .timing(chevronPos, { toValue: open ? 1 : 0, duration: 300, useNativeDriver: true })
      .start();
  }, [open]);

  const displayValue = options.find(({ value: oV }) => oV === value)?.label || placeholder;

  const commonItemProps = {
    flexDirection: 'row',
    alignItems: 'center',

    paddingLeft: 4,
    paddingRight: 3,
    paddingY: 3,

    borderWidth: 0.1,
    borderColor: 'grey',
  };

  const chevronAngle = chevronPos.interpolate({
    inputRange: [0, 1],
    outputRange: ['90deg', '-90deg'],
  });

  return (
    <ThemeProvider theme={Theme}>
      <Box noWrapTheme marginBottom={3} style={{ position: 'relative' }}>
        <Touchable
          disabled={disabled}
          testID={selectBoxID}
          noWrapTheme
          justifyContent="space-between"
          height={SELECT_HEIGHT}
          style={[
            {
              borderRadius: 5,
              tabIndex: 0,
              opacity: disabled ? 0.5 : 1,
            },
            open && {
              borderBottomLeftRadius: 0,
              borderBottomRightRadius: 0,
            },
          ]}
          onPress={() => setOpen((o) => !o)}
          {...commonItemProps}
        >
          <Box noWrapTheme flexDirection="row" alignItems="center">
            {iconPosition === 'right' && <Text touchable={false} noWrapTheme padding={0} marginRight={3} color={value ? null : 'grey'} fontSize={2} testID={selectBoxSelectedValueText}>{displayValue}</Text>}
            <SelectIcon {...{ Icon }} testID={selectBoxIconID} />
            {iconPosition === 'left' && <Text touchable={false} noWrapTheme padding={0} marginLeft={3} color={value ? null : 'grey'} fontSize={2} testID={selectBoxSelectedValueText}>{displayValue}</Text>}
          </Box>
          <Animated.Image
            source={require('../../assets/images/chevron.png')}
            style={{
              width: 10,
              height: 10,
              transform: [{ rotate: chevronAngle }]
            }}
          />
        </Touchable>
        {open && (
          <Scrollable
            testID={selectBoxOptionsContainer}
            noWrapTheme
            borderBottomLeftRadius={5}
            borderBottomRightRadius={5}
            borderWidth={commonItemProps.borderWidth}
            borderTopWidth={0}
            borderColor={commonItemProps.borderColor}
            overflow="hidden"
            onMouseLeave={() => setHighlighted('')}
            maxHeight={225}
            style={{
              position: 'absolute',
              top: SELECT_HEIGHT,
              width: '100%',
            }}
            contentContainerStyle={{paddingBottom: 0}}
          >
            {options.map(({ value: optValue, label, Icon: optIcon }, i) => {
              const isSelected = optValue === value;
              const isHighlighted = optValue === highlighted;

              return (
                <Touchable
                  testID={`${selectBoxOption}_${optValue}`}
                  noWrapTheme
                  tabIndex={0}
                  key={optValue}
                  backgroundColor={isHighlighted ? 'lightGrey' : 'white'}
                  justifyContent="space-between"
                  onPress={() => {
                    onSelect(optValue);
                    setOpen(false);
                  }}
                  onMouseEnter={() => setHighlighted(optValue)}
                  {...commonItemProps}
                  borderWidth={0}
                  borderBottomWidth={i === options.length - 1 ? 0 : commonItemProps.borderWidth}
                >
                  <Box noWrapTheme flexDirection="row" alignItems="center">
                    {iconPosition === 'right' && <Text noWrapTheme touchable={false} padding={0} marginRight={3} fontSize={2} testID={`${selectBoxOptionTextID}_${optValue}`}>{label}</Text>}
                    <SelectIcon {...{ Icon: optIcon }} testID={`${selectBoxOptionIconID}_${optValue}`} />
                    {iconPosition === 'left' && <Text noWrapTheme touchable={false} padding={0} marginLeft={3} fontSize={2} testID={`${selectBoxOptionTextID}_${optValue}`}>{label}</Text>}
                  </Box>

                  {isSelected && <Image source={require('../../assets/images/green_tick.png')} style={{ width: 15, height: 15 }} testID={`${selectBoxOptionCheckID}_${optValue}`} />}
                </Touchable>
              );
            })}
          </Scrollable>
        )}
      </Box>
    </ThemeProvider>
  );
}

export default SelectBox;
