import React, { useCallback, useMemo, useRef, useState } from 'react';
import { View } from 'react-native';
import type { ListRenderItem, StyleProp, ViewStyle } from 'react-native';
import { BottomSheetFlatList } from '@gorhom/bottom-sheet';
import CountryFlag from 'react-native-country-flag';
import FiltersSection from '../FiltersSection';
import CountryRow from './CountryRow';
import type { Country } from './CountryRow';
import SearchField from '../SearchField';
import GlobalFlagIcon, { globalFlagIconSize } from '../Icons/GlobalFlagIcon';
import Row from '../../componentsDS/Row';
import SearchBar from '../../componentsDS/SearchBar';
import { getSortedListOfCountries } from './utils';
import { resolveCountryShorthand } from './shorthand-map';
import { formatMessage } from '../../i18n';
import { safeWithTheme } from '../../branding';
import type { ThemeProps } from '../../branding/hoc/types';
import useHasFeature from '../../hooks/auth/useHasFeature';
import {
    MOBILE_BOTTOM_SHEET_SEARCH,
    MOBILE_COUNTRY_SHORTHAND_SEARCH
} from '../../constants/features';
import RegionQuickSelection from './RegionQuickSelection';
import type { RegionName } from '../../constants/regions';
import styles, { type Styles } from './styles';

const GLOBAL_COUNTRY: Country = { countryCode: 'GLOBAL', name: 'Global' };

interface FilterCountryProps {
    countriesSelected: Set<string> | string[];
    language?: string;
    onCountryPress: (country: Country) => void;
    style?: StyleProp<ViewStyle>;
    isMulti?: boolean;
    hasRedesignBottomSheet?: boolean;
    onRegionPillPress?: (region: RegionName) => void;
}

export const FilterCountry = ({
    countriesSelected,
    language,
    onCountryPress,
    style,
    theme,
    isMulti,
    hasRedesignBottomSheet,
    onRegionPillPress
}: FilterCountryProps & ThemeProps) => {
    const isShorthandEnabled = useHasFeature(MOBILE_COUNTRY_SHORTHAND_SEARCH);
    const hasBottomSheetSearch = useHasFeature(MOBILE_BOTTOM_SHEET_SEARCH);
    const hasSearchBar = Boolean(
        hasRedesignBottomSheet && hasBottomSheetSearch
    );
    const countries = useMemo(
        () => getSortedListOfCountries(language),
        [language]
    );
    const [queryRegExp, setQueryRegExp] = useState(new RegExp('', 'i'));
    const [rawQuery, setRawQuery] = useState('');
    const [showGlobal, setGlobalVisibility] = useState(true);
    const [pinnedCountryCodes, setPinnedCountryCodes] = useState(
        () => new Set<string>(countriesSelected)
    );
    const themeStyles = styles[theme] as unknown as Styles;

    const countryItems = Array.from(countriesSelected);
    const globalChecked =
        countryItems.length === 0 ||
        (countryItems.length === 1 && !countryItems[0]);

    const selectedCountryCodes = new Set<string>(countryItems);
    const selectedCountries = countries.filter(country =>
        selectedCountryCodes.has(country.countryCode)
    );
    const unselectedCountries = countries.filter(
        country => !selectedCountryCodes.has(country.countryCode)
    );
    const filteredUnselectedCountries = unselectedCountries.filter(country =>
        queryRegExp.test(country.name)
    );
    const shorthandCode = isShorthandEnabled
        ? resolveCountryShorthand(rawQuery.trim())
        : null;
    const shorthandCountry = shorthandCode
        ? unselectedCountries.find(c => c.countryCode === shorthandCode)
        : null;
    const orderedUnselectedCountries = shorthandCountry
        ? [
              shorthandCountry,
              ...filteredUnselectedCountries.filter(
                  c => c.countryCode !== shorthandCountry.countryCode
              )
          ]
        : filteredUnselectedCountries;

    const countriesSelectedRef = useRef(countriesSelected);
    countriesSelectedRef.current = countriesSelected;

    const onChangeQuery = useCallback((query: string) => {
        const trimmedQuery = query.trim();
        if (trimmedQuery) {
            setGlobalVisibility(false);
        } else {
            setGlobalVisibility(true);
            setPinnedCountryCodes(
                new Set<string>(countriesSelectedRef.current)
            );
        }
        const escapedQuery = trimmedQuery.replace(
            /[.*+?^${}()|[\]\\]/g,
            '\\$&'
        );
        const searchInputRegExp = new RegExp(`^${escapedQuery}`, 'i');
        setQueryRegExp(searchInputRegExp);
        setRawQuery(query);
    }, []);

    const onClear = useCallback(() => {
        setGlobalVisibility(true);
        setQueryRegExp(new RegExp('', 'i'));
        setRawQuery('');
    }, []);

    const onCountryPressRef = useRef(onCountryPress);
    onCountryPressRef.current = onCountryPress;
    const handleCountryPress = useCallback(
        (country: Country) => onCountryPressRef.current(country),
        []
    );

    const searchField = useMemo(
        () => (
            <SearchField
                style={themeStyles.searchBox}
                inputContainerStyle={themeStyles.searchBoxInput}
                onChangeQuery={onChangeQuery}
                onClear={onClear}
                onClearInput={onClear}
                placeholder={`${formatMessage('filtering.title')}...`}
            />
        ),
        [themeStyles, onChangeQuery, onClear]
    );

    if (hasSearchBar) {
        const isSearching = rawQuery.trim().length > 0;
        const searchResults = countries.filter(country =>
            queryRegExp.test(country.name)
        );
        const searchShorthandCountry = shorthandCode
            ? countries.find(c => c.countryCode === shorthandCode)
            : null;
        const orderedSearchResults = searchShorthandCountry
            ? [
                  searchShorthandCountry,
                  ...searchResults.filter(
                      c => c.countryCode !== searchShorthandCountry.countryCode
                  )
              ]
            : searchResults;
        const pinnedSelectedCountries = countries.filter(country =>
            pinnedCountryCodes.has(country.countryCode)
        );
        const unpinnedCountries = countries.filter(
            country => !pinnedCountryCodes.has(country.countryCode)
        );
        const listData: Country[] = isSearching
            ? orderedSearchResults
            : [
                  ...(showGlobal ? [GLOBAL_COUNTRY] : []),
                  ...pinnedSelectedCountries,
                  ...unpinnedCountries
              ];

        const renderItem: ListRenderItem<Country> = ({ item }) => {
            const isGlobal = item.countryCode === GLOBAL_COUNTRY.countryCode;
            return (
                <Row
                    variant="multiSelect"
                    label={
                        isGlobal
                            ? `${item.name} (${formatMessage(
                                  'home.topTracks.default'
                              )})`
                            : item.name
                    }
                    selected={
                        isGlobal
                            ? globalChecked
                            : selectedCountryCodes.has(item.countryCode)
                    }
                    onPress={() => handleCountryPress(item)}
                    icon={
                        isGlobal ? (
                            <GlobalFlagIcon size={globalFlagIconSize.s} />
                        ) : (
                            <CountryFlag
                                style={themeStyles.countryFlag}
                                isoCode={item.countryCode}
                                size={13}
                            />
                        )
                    }
                    testID="countryRow"
                />
            );
        };

        return (
            <View style={[themeStyles.searchListContainer, style]}>
                <SearchBar
                    value={rawQuery}
                    onChangeText={onChangeQuery}
                    placeholder={formatMessage(
                        'filtering.searchCountriesPlaceholder'
                    )}
                    clearAccessibilityLabel={formatMessage(
                        'filtering.searchClear'
                    )}
                    containerStyle={themeStyles.searchBar}
                />
                <BottomSheetFlatList
                    data={listData}
                    renderItem={renderItem}
                    keyExtractor={keyExtractor}
                    keyboardShouldPersistTaps="handled"
                    keyboardDismissMode="on-drag"
                    initialNumToRender={INITIAL_ROWS_TO_RENDER}
                    maxToRenderPerBatch={INITIAL_ROWS_TO_RENDER}
                    windowSize={WINDOW_SIZE}
                    style={themeStyles.redesignList}
                    contentContainerStyle={themeStyles.redesignListContent}
                />
            </View>
        );
    }

    const listHeader = () => (
        <View>
            {searchField}
            {onRegionPillPress ? (
                <RegionQuickSelection
                    selectedCountryCodes={countryItems}
                    onRegionPress={onRegionPillPress}
                />
            ) : null}
        </View>
    );

    if (hasRedesignBottomSheet) {
        const listData: Country[] = [
            ...(showGlobal ? [GLOBAL_COUNTRY] : []),
            ...selectedCountries,
            ...orderedUnselectedCountries
        ];

        const renderItem: ListRenderItem<Country> = ({ item }) => (
            <CountryRow
                hasRedesignBottomSheet
                country={item}
                checked={
                    item.countryCode === GLOBAL_COUNTRY.countryCode
                        ? globalChecked
                        : selectedCountryCodes.has(item.countryCode)
                }
                onPress={handleCountryPress}
                isMulti={isMulti}
            />
        );

        return (
            <BottomSheetFlatList
                data={listData}
                renderItem={renderItem}
                keyExtractor={keyExtractor}
                ListHeaderComponent={listHeader}
                keyboardShouldPersistTaps="handled"
                initialNumToRender={INITIAL_ROWS_TO_RENDER}
                maxToRenderPerBatch={INITIAL_ROWS_TO_RENDER}
                windowSize={WINDOW_SIZE}
                style={[themeStyles.redesignList, style]}
                contentContainerStyle={themeStyles.redesignListContent}
            />
        );
    }

    return (
        <View style={style}>
            <FiltersSection dividerVisible={false}>
                {searchField}
                {showGlobal ? (
                    <CountryRow
                        country={GLOBAL_COUNTRY}
                        checked={globalChecked}
                        onPress={onCountryPress}
                        isMulti={isMulti}
                    />
                ) : null}
                {selectedCountries.length ? (
                    <View>
                        {selectedCountries.map(country => (
                            <CountryRow
                                country={country}
                                checked={selectedCountryCodes.has(
                                    country.countryCode
                                )}
                                onPress={onCountryPress}
                                key={country.countryCode}
                                isMulti={isMulti}
                            />
                        ))}
                    </View>
                ) : null}
                {orderedUnselectedCountries.map(country => (
                    <CountryRow
                        country={country}
                        checked={selectedCountryCodes.has(country.countryCode)}
                        onPress={onCountryPress}
                        key={country.countryCode}
                        isMulti={isMulti}
                    />
                ))}
            </FiltersSection>
        </View>
    );
};

const INITIAL_ROWS_TO_RENDER = 12;
const WINDOW_SIZE = 11;

const keyExtractor = (country: Country) => country.countryCode;

export default safeWithTheme(FilterCountry);
