import { clsx } from 'clsx';
import { createRef, useEffect, useRef, useState } from 'react';

import Body from '../body';
import { Typography } from '../common';

type SegmentBase = { id: string; label: string; value: string };

type Segment = SegmentBase & { controls?: never };
type SegmentWithControls = SegmentBase & { controls: string };

export type Segments = readonly Segment[] | readonly SegmentWithControls[];

type SegmentedControlPropsBase = {
  name: string;
  value: string;
  mode: 'input' | 'view';
  onChange: (value: string) => void;
};

type SegmentedControlViewProps = {
  mode: 'view';
  segments: readonly SegmentWithControls[];
};

type SegmentedControlInputProps = {
  mode: 'input';
  segments: readonly Segment[];
};

export type SegmentedControlProps = SegmentedControlPropsBase &
  (SegmentedControlViewProps | SegmentedControlInputProps);

const SegmentedControl = ({
  name,
  value,
  mode = 'input',
  segments,
  onChange,
}: SegmentedControlProps) => {
  const [animate, setAnimate] = useState(false);

  const segmentsRef = useRef<HTMLDivElement>(null);

  if (segments.length > 3) {
    throw new Error(
      'SegmentedControl only supports up to 3 segments. Please refer to: https://wise.design/components/segmented-control',
    );
  }

  const segmentsWithRefs = segments.map((segment) => ({
    ...segment,
    ref: createRef<HTMLLabelElement | HTMLButtonElement>(),
  }));

  const updateSegmentPosition = () => {
    const selectedSegmentRef = segmentsWithRefs.find((segment) => segment.value === value)?.ref;

    // We grab the active segments style object from the ref
    // and set the css variables to the selected segments width and x position.
    // This is so we can animate the highlight to the selected segment
    if (selectedSegmentRef?.current && segmentsRef.current) {
      const { style } = segmentsRef.current;
      style.setProperty('--segment-highlight-width', `${selectedSegmentRef.current.offsetWidth}px`);
      style.setProperty('--segment-highlight-x', `${selectedSegmentRef.current.offsetLeft}px`);
    }
  };

  useEffect(() => {
    setAnimate(true);
    updateSegmentPosition();

    const handleWindowSizeChange = () => {
      setAnimate(false);
      updateSegmentPosition();
    };

    window.addEventListener('resize', handleWindowSizeChange);
    return () => {
      window.removeEventListener('resize', handleWindowSizeChange);
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [segmentsWithRefs, value]);

  return (
    <div
      ref={segmentsRef}
      data-testid="segmented-control"
      className={clsx('segmented-control', {
        'segmented-control--input': mode === 'input',
      })}
    >
      <div
        className={clsx('segmented-control__segments', {
          'segmented-control__segments--no-animate': !animate,
        })}
        role={mode !== 'input' ? 'tablist' : undefined}
      >
        {segmentsWithRefs.map((segment) => {
          const onSelect = () => {
            setAnimate(true);
            onChange(segment.value);
          };
          return mode === 'input' ? (
            <label
              ref={segment.ref as React.MutableRefObject<HTMLLabelElement | null>}
              key={segment.id}
              htmlFor={segment.id}
              className={clsx('segmented-control__segment', {
                'segmented-control__selected-segment': value === segment.value,
              })}
            >
              <input
                type="radio"
                className="segmented-control__radio-input"
                id={segment.id}
                name={name}
                value={segment.value}
                checked={value === segment.value}
                onChange={onSelect}
              />
              <Body
                className="segmented-control__text"
                as="span"
                type={
                  value === segment.value ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_DEFAULT
                }
              >
                {segment.label}
              </Body>
            </label>
          ) : (
            <button
              ref={segment.ref as React.MutableRefObject<HTMLButtonElement | null>}
              key={segment.id}
              type="button"
              role="tab"
              id={segment.id}
              aria-controls={segment.controls}
              aria-selected={value === segment.value}
              className={clsx('segmented-control__segment', 'segmented-control__button', {
                'segmented-control__selected-segment': value === segment.value,
              })}
              onClick={onSelect}
            >
              <Body
                as="span"
                className="segmented-control__text"
                type={
                  value === segment.value ? Typography.BODY_DEFAULT_BOLD : Typography.BODY_DEFAULT
                }
              >
                {segment.label}
              </Body>
            </button>
          );
        })}
      </div>
    </div>
  );
};

export default SegmentedControl;
