import ReactSelect, { components } from 'react-select'
import { Box, Flex, Text } from 'theme-ui'
import { useRef, useMemo } from 'react'
import { lighten } from 'polished'
import Image from 'next/image'

import { theme as themeBase } from '@/theme'
import { getPresetSlug } from '@/lib'

const previews = (() => {
  const { scope, ...presets } = require('./presets')

  return Object.values(presets).reduce((acc, { name }) => {
    const slug = getPresetSlug(name)
    acc[slug] = require(`../../public/preview/${slug}.png`).default
    return acc
  }, {})
})()

const Option = ({ innerRef, innerProps, children, value, ...props }) => (
  <components.Option {...props}>
    <Flex
      ref={innerRef}
      sx={{
        alignItems: 'center',
        justifyContent: 'space-between'
      }}
      {...innerProps}
    >
      <Text
        sx={{
          overflow: 'hidden',
          textOverflow: 'ellipsis',
          whiteSpace: 'nowrap',
          pr: 3,
          flex: 1
        }}
        title={children}
      >
        {children}
      </Text>
      <Box>
        <Image
          placeholder='blur'
          src={previews[value]}
          width={128}
          height={72}
        />
      </Box>
    </Flex>
  </components.Option>
)

const getStyles = ({ bg, color }) => {
  const secondaryColor = lighten(0.1, bg)

  const theme = () => {
    return {
      borderRadius: 4,
      colors: {
        primary: color,
        primary75: secondaryColor,
        primary50: secondaryColor,
        primary25: secondaryColor,
        danger: '#DE350B',
        dangerLight: '#FFBDAD',
        neutral0: bg,
        neutral5: color,
        neutral10: color,
        neutral20: color,
        neutral30: color,
        neutral40: color,
        neutral50: color,
        neutral60: color,
        neutral70: color,
        neutral80: color,
        neutral90: color
      },
      spacing: { baseUnit: 4, controlHeight: 38, menuGutter: 8 }
    }
  }

  const fontStyle = {
    fontFamily: themeBase.fonts.sans,
    fontSize: themeBase.fontSizes[1],
    fontWeight: themeBase.fontWeights.normal
  }

  const styles = {
    singleValue: provided => ({
      ...provided,
      ...fontStyle
    }),
    valueContainer: provided => ({
      ...provided,
      padding: '2px 8px'
    }),
    menu: provided => ({
      ...provided,
      ...fontStyle,
      minWidth: '300px',
      zIndex: 3
    }),
    option: (provided, { isFocused }) => ({
      ...provided,
      cursor: 'pointer',
      background: isFocused ? color : 'inherit',
      color: isFocused ? bg : 'inherit'
    }),
    indicatorSeparator: () => ({ display: 'none' }),
    control: (provided, { isFocused }) => ({
      ...provided,
      opacity: isFocused ? 1 : 0.75,
      cursor: 'pointer',
      boxShadow: 'none'
    })
  }

  return { theme, styles }
}

export const SearchableSelect = ({ bg, color, selectedValue, ...props }) => {
  const selectRef = useRef()

  const { styles, theme } = useMemo(() => getStyles({ bg, color }), [bg, color])

  const value = useMemo(
    () => props.options.find(({ value }) => value === selectedValue),
    [selectedValue, props.options]
  )

  const onMenuOpen = () =>
    setTimeout(() => {
      const { focusedOptionRef } = selectRef.current
      if (focusedOptionRef) {
        focusedOptionRef.scrollIntoView({ behavior: 'smooth' })
      }
    }, themeBase.speed.quickly)

  return (
    <ReactSelect
      onMenuOpen={onMenuOpen}
      ref={selectRef}
      components={{ Option }}
      styles={styles}
      theme={theme}
      value={value}
      {...props}
    />
  )
}