import { React } from '@gravityforms/libraries';
import { getValidLocale, sanitizeLocale } from '@gravityforms/utils';
import { getCountryCallingCode } from 'libphonenumber-js';

const NEEDS_I18N_LABEL = 'Needs i18n';

/**
 * @function getUnicodeFlag
 * @description Returns a Unicode flag emoji for a given ISO country code.
 *
 * @since 5.6.2
 *
 * @param {string} isoCode The ISO country code.
 *
 * @return {string} The Unicode flag emoji.
 */
export const getUnicodeFlag = ( isoCode ) => {
	if ( ! isoCode || isoCode.length !== 2 ) {
		return '';
	}
	// Convert ISO code to regional indicator symbols
	// e.g., 'U' (char code 85) becomes 0x1F1FA (regional indicator U)
	// The offset is 0x1F1E6 (base for regional indicators) - 0x41 ('A').
	return String.fromCodePoint(
		...isoCode.toUpperCase()
			.split( '' )
			.map( ( char ) => char.charCodeAt( 0 ) + ( 0x1F1E6 - 0x41 ) )
	);
};

/**
 * @function getCountriesListItemsFromIsos
 * @description Returns a list of countries for a given ISO country code.
 *
 * @since 5.6.2
 *
 * @param {Array}  isoCodes The ISO country codes.
 * @param {string} language The language to use for the country names.
 * @param {object} i18n     The i18n object.
 * @param {object} options  Options for the country list item.
 *
 * @return {Array} The list of countries.
 */
export const getCountriesListItemsFromIsos = ( isoCodes = [], language = 'en-US', i18n = {}, options = {} ) => {
	const { showFlag = true, showCallingCode = false, showPlaceholder = false } = options;
	const listItems = [];
	const locale = getValidLocale( sanitizeLocale( language ) );
	const countryNameProvider = new Intl.DisplayNames( [ locale ], { type: 'region' } );

	if ( showPlaceholder ) {
		listItems.push( {
			label: i18n?.placeholder || NEEDS_I18N_LABEL,
			value: '',
		} );
	}

	for ( const iso of isoCodes ) {
		try {
			const name = countryNameProvider.of( iso.toUpperCase() );
			if ( name === iso.toUpperCase() ) {
				// Intl.DisplayNames returns the code itself if it can't find a name.
				console.warn( `Could not find display name for ISO code: ${ iso }` );
			}

			let fullCallingCode = '';
			if ( showCallingCode ) {
				const callingCode = getCountryCallingCode( iso.toUpperCase() );
				fullCallingCode = `+${ callingCode }`;
			}

			listItems.push( {
				searchValue: `${ name } ${ fullCallingCode } ${ iso.toUpperCase() }`,
				label: name,
				value: iso.toUpperCase(),
				beforeLabel: showFlag ? <span className="gform-phone__flag-icon">{ getUnicodeFlag( iso.toUpperCase() ) }</span> : undefined,
				afterLabel: showCallingCode ? <span className="gform-phone__country-code">{ fullCallingCode }</span> : undefined,
			} );
		} catch ( error ) {
			// Handle cases where ISO code is invalid for getCountryCallingCode or other errors.
			console.error( `Error processing ISO code ${ iso }:`, error );
		}
	}

	return listItems;
};

/**
 * @function sortPreferredCountries
 * @description Sort the countries list items to set preferred countries first.
 *              If preferredCountries is empty, return the list as is.
 *              If preferredCountries is not empty, split the list into preferred and remaining countries.
 *
 * @since 5.5.0
 *
 * @param {Array}  listItems          List of countries.
 * @param {Array}  preferredCountries List of preferred countries.
 * @param {object} i18n               i18n object.
 *
 * @return {Array} The sorted countries list.
 */
export const sortPreferredCountries = ( listItems, preferredCountries, i18n ) => {
	if ( preferredCountries.length === 0 ) {
		return listItems;
	}

	let placeholder = null;
	const filteredListItems = listItems.filter( ( item ) => {
		if ( ! item.value ) {
			// Item is placeholder, remove it.
			placeholder = item;
			return false;
		}
		return true;
	} );

	const countryMap = new Map();
	filteredListItems.forEach( ( item ) => {
		countryMap.set( item.value, item );
	} );

	// Process the preferred countries in their specified order.
	const preferred = [];
	const usedISOs = new Set();
	preferredCountries.forEach( ( country ) => {
		const iso = typeof country === 'string' ? country : country?.value || country?.iso;
		if ( iso && countryMap.has( iso ) && ! usedISOs.has( iso ) ) {
			preferred.push( countryMap.get( iso ) );
			usedISOs.add( iso );
		}
	} );

	// If no preferred countries were found, return the list as is.
	if ( preferred.length === 0 ) {
		return listItems;
	}

	const remaining = filteredListItems.filter( ( item ) => ! usedISOs.has( item.value ) );
	if ( placeholder ) {
		preferred.unshift( placeholder );
	}

	// If no remaining countries were found, return the preferred list.
	if ( remaining.length === 0 ) {
		return preferred;
	}

	return [
		{
			type: 'group',
			items: preferred,
			label: i18n?.preferredCountries
				? {
					type: 'groupLabel',
					label: i18n.preferredCountries,
				}
				: undefined,
		},
		{
			type: 'group',
			items: remaining,
			label: i18n?.allCountries
				? {
					type: 'groupLabel',
					label: i18n.allCountries,
				}
				: undefined,
		},
	];
};
