import { useRef, useState } from 'react';
import { ActionButtonProps } from '../actionButton';
import { clsx } from 'clsx';
import Option from '../common/Option';
import type { OptionProps } from '../common/Option/Option';
import { Breakpoint, Position } from '../common';
import Section from '../section';
import Header from '../header';
import { HeaderProps } from '../header/Header';
import NavigationOption from '../navigationOption';
import NavigationOptionsList from '../navigationOptionsList';
import { useInputAttributes } from '../inputs/contexts';
import messages from './SelectOption.messages';
import { useIntl } from 'react-intl';
import ResponsivePanel from '../common/responsivePanel';
import { useScreenSize } from '../common/hooks/useScreenSize';
import { ChevronDown, Plus } from '@transferwise/icons';

export type SelectOptiopsSection<T = unknown> = {
  title?: HeaderProps['title'];
  options: SelectOptionValue<T>[];
};

export type SelectOptionValue<T = unknown> = Pick<
  OptionProps,
  'media' | 'title' | 'content' | 'disabled'
> & {
  value?: T;
};

export type SelectOptionPlaceholder = Pick<OptionProps, 'media' | 'title' | 'content'> & {
  actionLabel?: ActionButtonProps['children'];
};

export type SelectOptionProps<T = unknown> = {
  onChange: (selected: SelectOptionValue<T>) => void;
  selected?: SelectOptionValue<T>;
  options: SelectOptiopsSection<T>[];
  placeholder: SelectOptionPlaceholder;
} & Omit<
  OptionProps,
  'as' | 'title' | 'media' | 'content' | 'onClick' | 'onChange' | 'showMediaAtAllSizes' | 'decision'
>;

export default function SelectOption<T>({
  selected = undefined,
  options,
  onChange,
  placeholder,
  disabled,
  ...props
}: SelectOptionProps<T>) {
  const intl = useIntl();
  const rootRef = useRef(null);
  const [showOptions, setShowOptions] = useState(false);

  const hasSelected = selected !== undefined;
  const isLargeScreen = useScreenSize(Breakpoint.SMALL);

  const inputAttributes = useInputAttributes();
  const ariaLabelledBy = props['aria-labelledby'] ?? inputAttributes?.['aria-labelledby'];

  function handleOnClick(showOptionsStatus: boolean) {
    return () => {
      setShowOptions(showOptionsStatus);
    };
  }

  function handleOnChange(data: SelectOptionValue<T>) {
    return () => {
      setShowOptions(false);
      onChange(data);
    };
  }

  function getOptions(isLargeScreen = false) {
    return (
      <div className={clsx({ 'np-select-option-list': isLargeScreen })}>
        {options.map((optionsSection, index) => (
          <Section key={index} className={clsx({ 'p-x-2 p-y-1': isLargeScreen })}>
            {optionsSection.title && <Header title={optionsSection.title} />}
            <NavigationOptionsList>
              {optionsSection.options.map((option, index) => {
                return (
                  <NavigationOption
                    key={index}
                    isContainerAligned={!isLargeScreen}
                    showMediaCircle
                    showMediaAtAllSizes
                    onClick={handleOnChange(option)}
                    {...option}
                  />
                );
              })}
            </NavigationOptionsList>
          </Section>
        ))}
      </div>
    );
  }

  return (
    <>
      <Option
        ref={rootRef}
        as="div"
        showMediaAtAllSizes
        disabled={disabled}
        decision={false}
        media={hasSelected ? selected.media : (placeholder.media ?? <Plus size={24} />)}
        title={(hasSelected ? selected : placeholder).title}
        content={(hasSelected ? selected : placeholder).content}
        className={clsx(
          'np-select-option',
          'clickable',
          hasSelected ? 'np-select-option-selected' : 'np-select-option-placeholder',
          props.className,
        )}
        button={
          <button
            {...inputAttributes}
            type="button"
            disabled={disabled}
            aria-labelledby={ariaLabelledBy}
            aria-haspopup="dialog"
            aria-expanded={showOptions}
            className={hasSelected ? 'btn-unstyled' : 'np-action-btn'}
            aria-label={hasSelected ? undefined : props['aria-label']}
            onClick={handleOnClick(true)}
          >
            {hasSelected ? (
              <ChevronDown title={intl.formatMessage(messages.selectedActionLabel)} />
            ) : (
              placeholder.actionLabel || intl.formatMessage(messages.actionLabel)
            )}
          </button>
        }
      />
      <ResponsivePanel
        anchorWidth
        altAxis
        anchorRef={rootRef}
        open={showOptions}
        position={Position.BOTTOM}
        onClose={handleOnClick(false)}
      >
        {getOptions(isLargeScreen)}
      </ResponsivePanel>
    </>
  );
}
