import React, { useId } from 'react';
import { CountryFlag, GlyphIcon } from '@theorchard/suite-icons';
import { getCountryCallingCode, isSupportedCountry } from 'libphonenumber-js/min';
import cx from 'classnames';
import { Field } from '../field';
import { Select } from '../select';
import { SegmentedInput } from '../segmentedInput';
import { usePhoneInput } from './hooks/usePhoneInput';
import { t } from './i18n';
import { getExamplePlaceholder } from './utils';
import type { PhoneCountryCode, PhoneInputValue } from './types';
import type { SelectOption } from '../select';
import type { ComponentBaseProps } from '../../types';

const CLASS_NAME = 'PhoneInput';

export interface PhoneInputProps extends ComponentBaseProps {
    style?: React.CSSProperties;

    /** Ties the label to the input. Auto-generated when omitted. */
    controlId?: string;

    /** Selected country. Defaults to US. */
    country?: PhoneCountryCode;

    /** Controlled value (national format). Pass an E.164 string to round-trip a stored number. */
    value?: string;

    /** Initial value for uncontrolled mode. Accepts national or E.164. */
    defaultValue?: string;

    /** Initial country for uncontrolled mode. */
    defaultCountry?: PhoneCountryCode;

    /** Fired on every change with the parsed phone value. */
    onChange?: (phone: PhoneInputValue) => void;

    /** Label above the input. Defaults to `Phone Number`. */
    label?: string;

    /** Placeholder inside the number input. */
    placeholder?: string;

    /** Error message; puts the field in error state. */
    error?: string;

    /** Note rendered below the input. */
    note?: JSX.Element | string;

    /** Help tooltip next to the label. */
    helpText?: JSX.Element | string;

    disabled?: boolean;

    onFocus?: () => void;

    /** Fired on blur; validates and surfaces the invalid message when no `error` is set. */
    onBlur?: () => void;
}

const CountryInputValue: React.FC<{ value?: SelectOption }> = ({ value: opt }) => {
    const code = opt?.value as PhoneCountryCode | undefined;
    if (!code) return null;
    const callingCode = isSupportedCountry(code) ? getCountryCallingCode(code) : undefined;
    return (
        <span className={`${CLASS_NAME}-CountryTrigger-content`}>
            <CountryFlag countryCode={code} size={16} />
            {callingCode && (
                <span className={`${CLASS_NAME}-CountryTrigger-code`}>+{callingCode}</span>
            )}
        </span>
    );
};

const CountryDropdownIndicator: React.FC<{ menuOpen: boolean }> = ({ menuOpen }) => (
    <GlyphIcon name={menuOpen ? 'chevronUp' : 'chevronDown'} size={16} />
);

// Module-scope so the Select doesn't see a new components object on every PhoneInput render.
const SELECT_COMPONENTS = {
    InputValue: CountryInputValue,
    DropdownIndicator: CountryDropdownIndicator,
};

/**
 * Phone number field with a country selector. Formats as you type and validates against the selected country.
 *
 * @type molecule
 * @status live
 * @tags form-elements
 */
export const PhoneInput: React.FC<PhoneInputProps> = ({
    country: countryProp,
    value: valueProp,
    defaultValue,
    defaultCountry,
    onChange,
    label,
    placeholder,
    error,
    note,
    helpText,
    disabled,
    controlId,
    onFocus,
    onBlur,
    className,
    style,
    testId = CLASS_NAME,
}) => {
    const autoId = useId();
    const id = controlId ?? `${CLASS_NAME}-${autoId}`;

    const {
        country,
        value,
        countryOptions,
        selectedOption,
        resolvedError,
        inputRef,
        handleInputChange,
        handleCountryChange,
        handleBlur,
    } = usePhoneInput({
        countryProp,
        valueProp,
        defaultCountry,
        defaultValue,
        onChange,
        error,
        onBlur,
    });

    const message = resolvedError ? { type: 'error' as const, text: resolvedError } : undefined;

    return (
        <Field
            className={cx(CLASS_NAME, className)}
            style={style}
            testId={testId}
            controlId={id}
            labelText={label ?? t('label')}
            helpText={helpText}
            note={note}
            message={message}
        >
            <SegmentedInput disabled={disabled} className={`${CLASS_NAME}-segment`}>
                <Select
                    className={`${CLASS_NAME}-CountrySelect`}
                    options={countryOptions}
                    selectedValue={selectedOption}
                    onChange={handleCountryChange}
                    disabled={disabled}
                    hideClearButton
                    filterPlaceholder={t('searchPlaceholder')}
                    menuMinWidth={300}
                    menuMaxWidth={320}
                    width="auto"
                    components={SELECT_COMPONENTS}
                    testId={`${testId}-country`}
                />
                <input
                    ref={inputRef}
                    type="tel"
                    id={id}
                    className={cx('form-control', `${CLASS_NAME}-number`, { disabled })}
                    value={value}
                    placeholder={placeholder ?? getExamplePlaceholder(country) ?? t('placeholder')}
                    disabled={disabled}
                    aria-invalid={Boolean(resolvedError)}
                    onChange={(e) =>
                        handleInputChange(e.currentTarget.value, e.currentTarget.selectionStart)
                    }
                    onFocus={onFocus}
                    onBlur={handleBlur}
                    data-testid={`${testId}-number`}
                />
            </SegmentedInput>
        </Field>
    );
};
