import { clsx } from 'clsx';
import { useId, useState } from 'react';

import type { Step } from '../../stepper/Stepper';
import BottomSheet from '../../common/bottomSheet';
import Option from '../../common/Option';
import { Check, ChevronDown } from '@transferwise/icons';
import { OverlayIdContext, OverlayIdProvider } from '../../provider/overlay/OverlayIdProvider';
import List from '../../list';

export interface AnimatedLabelProps {
  activeLabel: number;
  className?: string;
  steps: readonly Step[];
}

const AnimatedLabel = ({ activeLabel, className, steps }: AnimatedLabelProps) => {
  const labelId = useId();
  const [showSteps, setShowSteps] = useState(false);

  function handleStepAction(onClick: Step['onClick']) {
    return () => {
      setShowSteps(false);
      onClick?.();
    };
  }

  return (
    <OverlayIdProvider open={showSteps}>
      <OverlayIdContext.Consumer>
        {(overlayId) => {
          return (
            <>
              <button
                type="button"
                id={labelId}
                aria-haspopup="menu"
                aria-controls={overlayId}
                aria-expanded={showSteps}
                className={clsx(
                  'np-animated-label',
                  'btn-unstyled',
                  'np-text-body-large-bold',
                  className,
                )}
                onClick={() => setShowSteps(true)}
              >
                {steps.map(({ label }, index) => {
                  const isCurrentStep = activeLabel === index;
                  const previousIndex = index - 1;
                  return (
                    <div
                      key={previousIndex}
                      aria-hidden={!isCurrentStep}
                      className={clsx('text-xs-center', 'd-inline-flex', 'align-items-center', {
                        'np-animated-label--active text-ellipsis': isCurrentStep,
                      })}
                    >
                      {label} <ChevronDown />
                    </div>
                  );
                })}
              </button>
              <BottomSheet
                role="menu"
                aria-labelledby={labelId}
                open={showSteps}
                onClose={() => setShowSteps(false)}
              >
                <List className="m-b-0 p-a-1">
                  {steps.map((step, index) => {
                    const isCurrentStep = activeLabel === index;
                    const isDisabled = activeLabel < index;
                    const itemId = `step-${index}`;
                    return (
                      <Option
                        key={itemId}
                        id={itemId}
                        as="li"
                        role="menuitem"
                        decision={false}
                        className={clsx('np-animated-label-option', 'p-x-3', 'p-y-1', 'm-y-1', {
                          clickable: !isDisabled,
                        })}
                        title={step.label}
                        content={step.hoverLabel}
                        button={isCurrentStep ? <Check size={24} /> : null}
                        aria-current={isCurrentStep ? 'step' : false}
                        aria-disabled={isDisabled}
                        disabled={isDisabled}
                        isContainerAligned
                        {...(!isDisabled && {
                          tabIndex: 0,
                          onClick: handleStepAction(step.onClick),
                          onKeyDown: (event) => {
                            event.preventDefault();
                            if (event.code === 'Enter' || event.code === 'Space') {
                              handleStepAction(step.onClick)();
                            }
                          },
                        })}
                      />
                    );
                  })}
                </List>
              </BottomSheet>
            </>
          );
        }}
      </OverlayIdContext.Consumer>
    </OverlayIdProvider>
  );
};

export default AnimatedLabel;
