import React, { useEffect, useRef, useState } from 'react';
import { View } from 'react-native';
import type { ListRenderItem, StyleProp, ViewStyle } from 'react-native';
import { debounce, isEmpty } from 'lodash';
import { BottomSheetFlatList } from '@gorhom/bottom-sheet';
import FiltersSection from '../FiltersSection';
import LabelRow from './LabelRow';
import type { Label } from './LabelRow';
import SearchField from '../SearchField';
import ZeroState from '../ZeroState';
import CenteredActivityIndicator from '../CenteredActivityIndicator';
import Row from '../../componentsDS/Row';
import SearchBar from '../../componentsDS/SearchBar';
import { getLabelId, getLabelType } from '../LabelRow/utils';
import { safeWithTheme } from '../../branding';
import type { ThemeProps } from '../../branding/hoc/types';
import { formatMessage } from '../../i18n';
import useSession from '../../hooks/auth/useSession';
import useLabelSearch from '../../hooks/useLabelSearch';
import useHasFeature from '../../hooks/auth/useHasFeature';
import { MOBILE_BOTTOM_SHEET_SEARCH } from '../../constants/features';
import { SEARCH_DEBOUNCE } from '../../constants';
import styles, { type Styles } from './styles';

export const getIsLabelSelected = (
    label: Label,
    labelsSelected: Label[]
): boolean => {
    const labelId = getLabelId(label);
    return labelsSelected.some(ls => labelId === getLabelId(ls));
};

const getLabelRowTitle = (label: Label) =>
    `${label.name} (${label.id?.subaccountId || label.id?.vendorId})`;

const getLabelRowDisclaimer = (label: Label) => {
    const type = getLabelType(label);
    return label.vendor
        ? `${type} • ${label.vendor.name} (${label.vendor.id?.vendorId})`
        : type;
};

interface FilterLabelProps {
    labelsSelected: Label[];
    onLabelPress: (label: Label) => void;
    style?: StyleProp<ViewStyle>;
    hasRedesignBottomSheet?: boolean;
}

export const FilterLabel = ({
    labelsSelected,
    onLabelPress,
    theme,
    style,
    hasRedesignBottomSheet
}: FilterLabelProps & ThemeProps) => {
    const [session] = useSession();
    const { labelAccess } = session.currentProfile;
    const { query, changeQuery, clearQuery, labels, loading } = useLabelSearch({
        labelAccess
    });
    const hasBottomSheetSearch = useHasFeature(MOBILE_BOTTOM_SHEET_SEARCH);
    const hasSearchBar = Boolean(
        hasRedesignBottomSheet && hasBottomSheetSearch
    );
    const [searchInputValue, setSearchInputValue] = useState('');
    const [pinnedLabels, setPinnedLabels] = useState(labelsSelected);
    const themeStyles = styles[theme] as unknown as Styles;

    const changeQueryRef = useRef(changeQuery);
    changeQueryRef.current = changeQuery;
    const debouncedChangeQuery = useRef(
        debounce(
            (term: string) => changeQueryRef.current(term),
            SEARCH_DEBOUNCE
        )
    ).current;

    useEffect(
        () => () => debouncedChangeQuery.cancel(),
        [debouncedChangeQuery]
    );

    const handleSearchTextChange = (text: string) => {
        setSearchInputValue(text);
        const trimmedText = text.trim();
        if (trimmedText) {
            debouncedChangeQuery(trimmedText);
        } else {
            debouncedChangeQuery.cancel();
            clearQuery();
            setPinnedLabels(labelsSelected);
        }
    };

    const getLabels = () => {
        const selectedLabelNames = labelsSelected.map(label => label.name);
        const otherLabels = labels.filter(
            label => !selectedLabelNames.includes(label.name)
        );

        return (
            <>
                {labelsSelected.length && !query ? (
                    <View>
                        {labelsSelected.map(label => (
                            <LabelRow
                                onPress={() => onLabelPress(label)}
                                label={label}
                                checked={getIsLabelSelected(
                                    label,
                                    labelsSelected
                                )}
                                key={getLabelId(label)}
                            />
                        ))}
                    </View>
                ) : null}
                {otherLabels.map(label => (
                    <LabelRow
                        onPress={() => onLabelPress(label)}
                        label={label}
                        checked={getIsLabelSelected(label, labelsSelected)}
                        key={getLabelId(label)}
                    />
                ))}
            </>
        );
    };

    if (hasSearchBar) {
        const isSearching = !isEmpty(query);
        const listData = isSearching
            ? labels
            : [
                  ...pinnedLabels,
                  ...labels.filter(
                      label => !getIsLabelSelected(label, pinnedLabels)
                  )
              ];

        const renderItem: ListRenderItem<Label> = ({ item }) => (
            <Row
                variant="multiSelect"
                label={getLabelRowTitle(item)}
                disclaimer={getLabelRowDisclaimer(item)}
                selected={getIsLabelSelected(item, labelsSelected)}
                onPress={() => onLabelPress(item)}
                testID={getLabelId(item)}
            />
        );

        return (
            <View style={[themeStyles.container, style]}>
                <SearchBar
                    value={searchInputValue}
                    onChangeText={handleSearchTextChange}
                    placeholder={formatMessage(
                        'filtering.searchLabelsPlaceholder'
                    )}
                    clearAccessibilityLabel={formatMessage(
                        'filtering.searchClear'
                    )}
                    containerStyle={themeStyles.searchBar}
                />
                {loading ? (
                    <CenteredActivityIndicator />
                ) : isEmpty(listData) ? (
                    <ZeroState
                        style={themeStyles.zeroState}
                        title={formatMessage('addLabels.zeroState.title', {
                            term: query
                        })}
                        message={formatMessage('addLabels.zeroState.message')}
                    />
                ) : (
                    <BottomSheetFlatList
                        data={listData}
                        renderItem={renderItem}
                        keyExtractor={getLabelId}
                        keyboardShouldPersistTaps="handled"
                        keyboardDismissMode="on-drag"
                        style={themeStyles.searchList}
                        contentContainerStyle={themeStyles.searchListContent}
                    />
                )}
            </View>
        );
    }

    return (
        <View style={[themeStyles.container, style]}>
            <FiltersSection dividerVisible={false}>
                <SearchField
                    style={themeStyles.searchBox}
                    inputContainerStyle={themeStyles.searchBoxInput}
                    onChangeQuery={changeQuery}
                    onClear={clearQuery}
                    onClearInput={clearQuery}
                    placeholder={`${formatMessage('filtering.title')}...`}
                />
                {loading ? (
                    <CenteredActivityIndicator />
                ) : isEmpty(labels) ? (
                    <ZeroState
                        style={themeStyles.zeroState}
                        title={formatMessage('addLabels.zeroState.title', {
                            term: query
                        })}
                        message={formatMessage('addLabels.zeroState.message')}
                    />
                ) : (
                    getLabels()
                )}
            </FiltersSection>
        </View>
    );
};

export default safeWithTheme(FilterLabel);
