import { FocusEvent, ReactNode } from 'react';
import { FieldValues, useController, UseControllerProps } from 'react-hook-form';
import {
	FormControl,
	FormControlLabel,
	FormControlLabelProps,
	FormControlProps,
	FormHelperText,
	FormHelperTextProps,
	FormLabel,
	FormLabelProps,
	Radio,
	RadioGroup,
	RadioGroupProps,
	RadioProps
} from '@mui/material';
import { isBoolean, isString, isUndefined } from 'lodash';

import { useDefaultProps } from '../../hooks';
import { useLocalization } from '../../localization';

export interface RadioOption {
	value: string;
	label: ReactNode;

	slotProps?: {
		formControlLabel: Omit<FormControlLabelProps, 'key' | 'value' | 'label' | 'control'>;
		radio: RadioProps;
	};
}

export type RHFRadioGroupProps<T extends FieldValues = FieldValues> = UseControllerProps<T> &
	Omit<RadioProps, 'value' | 'checked'> & {
		label: string;
		options: RadioOption[];
		required?: boolean;
		helperText?: string;
		onChange?: RadioGroupProps['onChange'];
		onBlur?: RadioGroupProps['onBlur'];

		slotProps?: {
			formLabel?: FormLabelProps;
			formControl?: Omit<FormControlProps, 'name' | 'disabled' | 'error' | 'children' | 'defaultValue'>;
			radioGroup?: Omit<RadioGroupProps, 'onChange' | 'onBlur' | 'name' | 'value'>;
			helperText?: FormHelperTextProps;
			formControlLabel?: Omit<FormControlLabelProps, 'key' | 'value' | 'label' | 'control'>;
		};
	};

function RHFRadioGroup<T extends FieldValues>(inProps: RHFRadioGroupProps<T>) {
	const {
		/** React Hook Form */
		name,
		rules,
		control,
		disabled,
		defaultValue,
		shouldUnregister,
		/** React Hook Form */

		label,
		options,
		required,
		onChange,
		onBlur,
		helperText,

		slotProps,
		...radioProps
	} = useDefaultProps({ name: 'ReevolveRHFRadioGroup', props: inProps });

	const { translate } = useLocalization();

	const {
		field,
		fieldState: { error }
	} = useController<T>({
		name,
		defaultValue,
		shouldUnregister,
		disabled,
		control,
		rules: rules && {
			...rules,
			required: rules?.required === true ? translate('validation.required', { label }) : rules?.required
		}
	});

	function onChangeHandler(event: React.ChangeEvent<HTMLInputElement>, value: string) {
		field.onChange(value);
		onChange?.(event, value);
	}

	function onBlurHandler(e: FocusEvent<HTMLDivElement, Element>) {
		field.onBlur();
		onBlur?.(e);
	}

	return (
		<FormControl
			{...slotProps?.formControl}
			error={!!error}
			disabled={field.disabled}
			required={
				isBoolean(rules?.required) ? rules.required : isString(rules?.required) || rules?.required?.value || required
			}
		>
			{label && <FormLabel {...slotProps?.formLabel}>{label}</FormLabel>}
			<RadioGroup
				row
				{...slotProps?.radioGroup}
				name={field.name}
				value={isUndefined(field.value) ? null : field.value}
				onBlur={onBlurHandler}
				onChange={onChangeHandler}
			>
				{options.map((option) => (
					<FormControlLabel
						ref={field.ref}
						{...slotProps?.formControlLabel}
						{...option.slotProps?.formControlLabel}
						key={option.value}
						value={option.value}
						label={option.label}
						control={
							<Radio
								{...radioProps}
								{...option.slotProps?.radio}
							/>
						}
					/>
				))}
			</RadioGroup>

			{(error?.message || helperText) && (
				<FormHelperText {...slotProps?.helperText}>{error?.message || helperText}</FormHelperText>
			)}
		</FormControl>
	);
}

declare module '@mui/material' {
	interface Components {
		ReevolveRHFRadioGroup?: {
			defaultProps?: Partial<RHFRadioGroupProps>;
		};
	}
}

export default RHFRadioGroup;
