import { jsx as _jsx } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { CircleFlag } from 'react-circle-flags';
import countries from 'world-countries';
import parsePhoneNumber, { getCountryCallingCode } from 'libphonenumber-js';
const renderFlagIcon = (countryCode) => {
    return _jsx(CircleFlag, { className: "size-4", countryCode: countryCode.toLowerCase(), height: 16 });
};
const getCallingCode = (countryCode) => {
    try {
        const callingCode = getCountryCallingCode(countryCode);
        return `+${callingCode}`;
    }
    catch {
        return null;
    }
};
const parsePhoneValue = (rawValue) => {
    if (rawValue === '')
        return null;
    const withPlusValue = `${rawValue.startsWith('+') ? '' : '+'}${rawValue}`;
    const parsedValue = parsePhoneNumber(withPlusValue, { extract: false });
    if (parsedValue?.isPossible() && parsedValue.country) {
        const expectedValue = `+${parsedValue.countryCallingCode}${parsedValue.nationalNumber}`;
        if (withPlusValue !== expectedValue) {
            return null; // the number was corrected by the library, reject it
        }
        const callingCode = `+${parsedValue.countryCallingCode}`;
        const selectValue = `${callingCode}-${parsedValue.country}`;
        const inputValue = parsedValue.nationalNumber;
        return { selectValue, inputValue };
    }
    return null;
};
export const usePhoneNumberInput = ({ value, defaultValue, onChange, onKeyDown, onBlur, allowedCountries, excludedCountries, includeDependentAreas = false, prefixOptionFormat = 'FlagsAndNumbers', externalRef, }) => {
    const inputRef = useRef(null);
    const containerRef = useRef(null);
    const isInternalChangeRef = useRef(false);
    const lastCursorPositionRef = useRef(0);
    const mergedRef = (node) => {
        inputRef.current = node;
        if (typeof externalRef === 'function') {
            externalRef(node);
        }
        else if (externalRef) {
            externalRef.current = node;
        }
    };
    const [selectValue, setSelectValue] = useState(() => {
        const parsedValue = parsePhoneValue(value ?? defaultValue ?? '');
        return parsedValue?.selectValue ?? '';
    });
    const [inputValue, setInputValue] = useState(() => {
        const rawValue = value ?? defaultValue ?? '';
        const parsedValue = parsePhoneValue(rawValue);
        return parsedValue?.inputValue ?? rawValue;
    });
    const options = useMemo(() => {
        const defaultOptions = countries
            .filter((country) => (includeDependentAreas ? true : country.independent) &&
            country.cca2 !== 'AQ' && // exclude Antarctica
            getCallingCode(country.cca2) !== null // only countries with calling codes
        )
            .map((country) => {
            const callingCode = getCallingCode(country.cca2);
            const countryCode = country.cca2;
            let label = '';
            let icon = undefined;
            switch (prefixOptionFormat) {
                case 'CodesOnly':
                    label = countryCode;
                    break;
                case 'FlagsOnly':
                    label = '';
                    icon = () => renderFlagIcon(countryCode);
                    break;
                case 'FlagsAndCodes':
                    label = countryCode;
                    icon = () => renderFlagIcon(countryCode);
                    break;
                case 'FlagsAndNumbers':
                default:
                    label = callingCode;
                    icon = () => renderFlagIcon(countryCode);
                    break;
            }
            return {
                value: `${callingCode}-${countryCode}`,
                label,
                icon,
            };
        })
            .sort((a, b) => {
            const aCode = parseInt(a.value.split('-')[0].replace('+', ''));
            const bCode = parseInt(b.value.split('-')[0].replace('+', ''));
            return aCode - bCode;
        });
        const allowedCountriesArray = Array.isArray(allowedCountries) ? allowedCountries : undefined;
        const excludedCountriesArray = Array.isArray(excludedCountries) ? excludedCountries : undefined;
        const filteredOptions = allowedCountriesArray || excludedCountriesArray
            ? defaultOptions.filter((option) => {
                const countryCode = option.value.split('-')[1];
                const isAllowedCountry = allowedCountriesArray ? allowedCountriesArray.includes(countryCode) : true;
                const isExcludedCountry = excludedCountriesArray ? !excludedCountriesArray.includes(countryCode) : true;
                return isAllowedCountry && isExcludedCountry;
            })
            : defaultOptions;
        return filteredOptions;
    }, [allowedCountries, excludedCountries, includeDependentAreas, prefixOptionFormat]);
    const handleSelectBlur = useCallback((e) => {
        setTimeout(() => {
            const activeElement = document.activeElement;
            const container = containerRef.current;
            if (container && activeElement && container.contains(activeElement)) {
                return;
            }
            onBlur?.(e);
        }, 0);
    }, [onBlur]);
    const handleInputBlur = useCallback((e) => {
        setTimeout(() => {
            const activeElement = document.activeElement;
            const container = containerRef.current;
            if (container && activeElement && container.contains(activeElement)) {
                return;
            }
            onBlur?.(e);
        }, 0);
    }, [onBlur]);
    const handleSelectOnChange = useCallback((newSelectValue) => {
        setSelectValue(newSelectValue);
        const callingCode = newSelectValue.split('-')[0];
        isInternalChangeRef.current = true;
        onChange?.(`${callingCode}${inputValue}`);
        inputRef.current?.focus();
    }, [inputValue, onChange]);
    const handleInputOnChange = useCallback((e) => {
        // save cursor position
        lastCursorPositionRef.current = e.target.selectionStart ?? 0;
        let callingCode = selectValue.split('-')[0];
        let inputValueToProcess = e.target.value.replace(/\D/g, '');
        if (selectValue === '' && inputValueToProcess.startsWith('00')) {
            inputValueToProcess = `+${inputValueToProcess.substring(2)}`;
        }
        const parsedValue = parsePhoneValue(`${callingCode}${inputValueToProcess}`);
        if (selectValue === '' && parsedValue && options.some((o) => o.value === parsedValue.selectValue)) {
            setSelectValue(parsedValue.selectValue);
            setInputValue(parsedValue.inputValue);
            callingCode = parsedValue.selectValue.split('-')[0];
            isInternalChangeRef.current = true;
            onChange?.(`${callingCode}${parsedValue.inputValue}`);
        }
        else {
            const newInputValue = e.target.value.replace(/\D/g, '');
            setInputValue(newInputValue);
            isInternalChangeRef.current = true;
            onChange?.(`${callingCode}${newInputValue}`);
        }
    }, [selectValue, options, onChange]);
    const handleOnKeyDown = useCallback((e) => {
        const isCopyShortcut = (e.ctrlKey && (e.key === 'c' || e.key === 'C')) || (e.metaKey && (e.key === 'c' || e.key === 'C'));
        const isCutShortcut = (e.ctrlKey && (e.key === 'x' || e.key === 'X')) || (e.metaKey && (e.key === 'x' || e.key === 'X'));
        const isPasteShortcut = (e.ctrlKey && (e.key === 'v' || e.key === 'V')) || (e.metaKey && (e.key === 'v' || e.key === 'V'));
        const isSelectAllShortcut = (e.ctrlKey && (e.key === 'a' || e.key === 'A')) || (e.metaKey && (e.key === 'a' || e.key === 'A'));
        const allowed = new Set([
            'Backspace',
            'Delete',
            'ArrowLeft',
            'ArrowRight',
            'ArrowUp',
            'ArrowDown',
            'Home',
            'End',
            'Tab',
            'Enter',
            'Escape',
        ]);
        const isDigit = /^[0-9]$/.test(e.key);
        if (isCopyShortcut || isCutShortcut || isPasteShortcut || isSelectAllShortcut || allowed.has(e.key) || isDigit) {
            onKeyDown?.(e);
            return;
        }
        e.preventDefault();
        onKeyDown?.(e);
    }, [onKeyDown]);
    useEffect(() => {
        if (value !== undefined) {
            if (isInternalChangeRef.current) {
                isInternalChangeRef.current = false;
                return;
            }
            if (value === '') {
                setSelectValue('');
                setInputValue('');
                return;
            }
            const parsedValue = parsePhoneValue(value);
            if (parsedValue && options.some((o) => o.value === parsedValue.selectValue)) {
                setSelectValue(parsedValue.selectValue);
                setInputValue(parsedValue.inputValue);
            }
            else {
                setSelectValue('');
                setInputValue(value);
            }
        }
    }, [value, options]);
    // restore cursor position after input value change
    useEffect(() => {
        if (inputRef.current && lastCursorPositionRef.current > 0) {
            const position = Math.min(lastCursorPositionRef.current, inputValue.length);
            inputRef.current.setSelectionRange(position, position);
        }
    }, [inputValue]);
    return {
        options,
        selectValue,
        inputValue,
        handleSelectOnChange,
        handleInputOnChange,
        handleOnKeyDown,
        handleSelectBlur,
        handleInputBlur,
        mergedRef,
        containerRef,
    };
};
//# sourceMappingURL=use-phone-number-input.js.map