import clsx from "clsx";
import { ChangeEvent, FC, HTMLAttributes, useRef, useState } from "react";

import styles from "./styles.module.css";

export interface RadioOption {
  label: string;
  value: string | number;
  description?: string;
  disabled?: boolean;
}

export interface RadioGroupProps
  extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
  name: string;
  initialValue?: string | number;
  title: string;
  options: RadioOption[];
  description?: string;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
  onChangeConfirm?: (
    e: ChangeEvent<HTMLInputElement>,
    newValue: string | number,
    oldValue: string | number,
    accept: () => void,
    reject: () => void
  ) => void;
  disabled?: boolean;
  themed?: boolean;
}

export const RadioGroup: FC<RadioGroupProps> = ({
  className,
  name,
  initialValue,
  title,
  options,
  description,
  disabled,
  onChange,
  onChangeConfirm,
  themed,
  ...props
}) => {
  const radioGroupRef = useRef<HTMLDivElement>(null!);
  const [selectedValue, setSelectedValue] = useState(
    initialValue || options[0]?.value
  );

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    const newValue =
      typeof selectedValue === "number"
        ? Number(e.target.value)
        : e.target.value;

    if (onChangeConfirm) {
      onChangeConfirm(
        e,
        newValue,
        selectedValue,
        () => {
          if (onChange) onChange(e);
          setSelectedValue(newValue);
        },
        () => {
          // noop
        }
      );
    } else {
      if (onChange) onChange(e);
      setSelectedValue(newValue);
    }
  };

  return (
    <div
      className={clsx([styles.radioGroup, themed && styles.themed, className])}
      ref={radioGroupRef}
      {...props}
    >
      <legend>{title}</legend>
      {description && <p className={styles.subtitle}>{description}</p>}
      <div className={styles.options}>
        {options?.map((option) => {
          const id = `${name}_${option.value}`;
          const checked = String(selectedValue) === String(option.value);

          return (
            <div
              className={styles.option}
              key={id}
              data-testid="radio-option-container"
            >
              <input
                type="radio"
                name={name}
                id={id}
                onChange={handleChange}
                value={option.value}
                aria-checked={checked}
                disabled={disabled || option.disabled}
              />
              <div className={styles.content}>
                <label className={styles.label} htmlFor={id}>
                  {option.label}
                </label>
                {option.description && (
                  <p className={styles.description}>{option.description}</p>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};
