import type { InputHTMLAttributes, RefCallback } from 'react';
import { useImperativeHandle, useMemo, useRef } from 'react';
import cn from 'clsx';
import PhoneInput from 'react-phone-number-input';
import { getLabels } from './getLabels';
import type { Props } from 'react-phone-number-input';
import 'react-phone-number-input/style.css';

type PhoneInputProps = Props<object>;

export type PhoneNumberInputProps = Omit<
    PhoneInputProps,
    'numberInputProps'
> & {
    locale?: string;
    isError?: boolean;
    errorClassName?: string;
    placeholder?: string;
    internationalCodeLabel?: string;
    // Country `<select/>` uses this as its default `aria-label`.
    countryLabel?: string;
    // Can be used as a label for phone number input.
    phoneLabel?: string;
    // Can be used as a label for phone number extension input.
    extLabel?: string;
    numberInputProps?: InputHTMLAttributes<HTMLInputElement>;
    innerRef?: RefCallback<unknown>;
};

export function PhoneNumberInput({
    innerRef,
    numberInputProps,
    isError,
    errorClassName,
    placeholder,
    internationalCodeLabel,
    countryLabel,
    phoneLabel,
    extLabel,
    ...props
}: PhoneNumberInputProps) {
    const internalRef = useRef<HTMLInputElement>(null);

    // 'ref' fix for 'react-hook-form' controlled input
    useImperativeHandle(innerRef, () => ({
        focus() {
            if (internalRef.current) {
                internalRef.current.focus();
            }
        },
    }));

    const labels = useMemo(() => {
        const localizedLabels = getLabels({ locale: props.locale });

        localizedLabels.country = countryLabel;
        localizedLabels.phone = phoneLabel;
        localizedLabels.ext = extLabel;
        localizedLabels.ZZ = internationalCodeLabel || 'International';

        return localizedLabels;
    }, [
        props.locale,
        internationalCodeLabel,
        countryLabel,
        phoneLabel,
        extLabel,
    ]);

    const composedNumberInputProps = {
        ...numberInputProps,
        className: cn([numberInputProps?.className, isError && errorClassName]),
    };

    return (
        <PhoneInput
            // @ts-expect-error ref is attached to inner input element
            ref={internalRef}
            labels={labels}
            placeholder={placeholder}
            numberInputProps={composedNumberInputProps}
            {...props}
        />
    );
}
