import React, {useEffect, useMemo, useRef, useState} from 'react';

import {useIntl} from 'react-intl';
import {Client4} from 'mattermost-redux/client';
import {UserProfile} from 'mattermost-redux/types/users';

import {debounce, getUserDisplayName} from 'utils/helpers';
import CloseIcon from 'components/icons/close_icon';
import SearchIcon from 'components/icons/search_icon';

import './user_multi_select.scss';

type SelectedUser = {
    id: string;
    username: string;
    fullName: string;
    avatarUrl: string;
}

type Props = {
    value: string;
    onChange: (value: string) => void;
    placeholder?: string;
    disabled?: boolean;
}

const UserMultiSelect: React.FC<Props> = ({value, onChange, placeholder, disabled}) => {
    const intl = useIntl();
    const containerRef = useRef<HTMLDivElement>(null);
    const inputRef = useRef<HTMLInputElement>(null);

    const [searchTerm, setSearchTerm] = useState('');
    const [results, setResults] = useState<UserProfile[]>([]);
    const [dropdownOpen, setDropdownOpen] = useState(false);
    const [loading, setLoading] = useState(false);
    const [profilesLoading, setProfilesLoading] = useState(false);
    const [selectedUsers, setSelectedUsers] = useState<SelectedUser[]>([]);

    const loadedValueRef = useRef<string | null>(null);

    useEffect(() => {
        let cancelled = false;

        if (loadedValueRef.current === value) {
            // Already synced — nothing to do
        } else if (value) {
            const usernames = value.split(',').map((u) => u.trim()).filter(Boolean);
            if (usernames.length === 0) {
                setSelectedUsers([]);
                loadedValueRef.current = value;
            } else {
                setProfilesLoading(true);
                Promise.all(usernames.map(async (username) => {
                    try {
                        const user = await Client4.getUserByUsername(username);
                        return {
                            id: user.id,
                            username: user.username,
                            fullName: getUserDisplayName(user),
                            avatarUrl: Client4.getProfilePictureUrl(user.id, user.last_picture_update),
                        };
                    } catch {
                        return {id: '', username, fullName: '', avatarUrl: ''};
                    }
                })).then((users) => {
                    if (!cancelled) {
                        setSelectedUsers(users);
                        loadedValueRef.current = value;
                        setProfilesLoading(false);
                    }
                });
            }
        } else {
            setSelectedUsers([]);
            setProfilesLoading(false);
            loadedValueRef.current = '';
        }

        return () => {
            cancelled = true;
        };
    }, [value]);

    useEffect(() => {
        const handleClickOutside = (e: MouseEvent) => {
            if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
                setDropdownOpen(false);
                setSearchTerm('');
            }
        };
        document.addEventListener('mousedown', handleClickOutside);
        return () => document.removeEventListener('mousedown', handleClickOutside);
    }, []);

    const performSearch = async (term: string, excluded: Set<string>) => {
        if (!term) {
            setResults([]);
            setDropdownOpen(false);
            setLoading(false);
            return;
        }
        setLoading(true);
        try {
            const data = await Client4.autocompleteUsers(term, '', '', {limit: 20});
            setResults(data.users.filter((u) => !excluded.has(u.username) && !(u as UserProfile & {remote_id?: string}).remote_id));
        } catch {
            setResults([]);
        } finally {
            setLoading(false);
        }
    };

    const doSearch = useMemo(() => debounce(performSearch, 400), []);

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const term = e.target.value;
        setSearchTerm(term);
        if (term) {
            setDropdownOpen(true);
        }
        doSearch(term, new Set(selectedUsers.map((u) => u.username)));
    };

    const handleSelect = (user: UserProfile) => {
        const next = [...selectedUsers, {
            id: user.id,
            username: user.username,
            fullName: getUserDisplayName(user),
            avatarUrl: Client4.getProfilePictureUrl(user.id, user.last_picture_update),
        }];
        setSelectedUsers(next);
        const newValue = next.map((u) => u.username).join(', ');
        loadedValueRef.current = newValue;
        onChange(newValue);
        setSearchTerm('');
        setResults([]);
        setDropdownOpen(false);
        inputRef.current?.focus();
    };

    const handleRemove = (username: string) => {
        const next = selectedUsers.filter((u) => u.username !== username);
        setSelectedUsers(next);
        const newValue = next.map((u) => u.username).join(', ');
        loadedValueRef.current = newValue;
        onChange(newValue);
    };

    const placeholderText = placeholder || intl.formatMessage({
        id: 'badges.admin.placeholder',
        defaultMessage: 'Начните вводить имя...',
    });

    return (
        <div
            className='user-multi-select'
            ref={containerRef}
        >
            <div
                className='user-multi-select__container'
                onClick={() => inputRef.current?.focus()}
            >
                {(loading || profilesLoading) ? (
                    <div className='user-multi-select__spinner'/>
                ) : (
                    <SearchIcon/>
                )}
                {profilesLoading ? null : selectedUsers.map((user) => (
                    <span
                        key={user.username}
                        className='user-multi-select__chip'
                    >
                        {user.avatarUrl && (
                            <img
                                className='user-multi-select__chip-avatar'
                                src={user.avatarUrl}
                                alt={user.username}
                            />
                        )}
                        <span className='user-multi-select__chip-name'>
                            {user.fullName || user.username}
                        </span>
                        {!disabled && (
                            <button
                                type='button'
                                className='user-multi-select__chip-remove'
                                onClick={(e) => {
                                    e.stopPropagation();
                                    handleRemove(user.username);
                                }}
                            >
                                <CloseIcon size={12}/>
                            </button>
                        )}
                    </span>
                ))}
                <input
                    ref={inputRef}
                    className='user-multi-select__input'
                    type='text'
                    value={searchTerm}
                    disabled={disabled}
                    onChange={handleInputChange}
                    placeholder={selectedUsers.length === 0 ? placeholderText : ''}
                />
            </div>
            {dropdownOpen && (
                <div className='user-multi-select__dropdown'>
                    {results.length === 0 && searchTerm && (
                        <div className={`user-multi-select__no-results${loading ? ' user-multi-select__no-results--loading' : ''}`}>
                            {intl.formatMessage({
                                id: 'badges.admin.no_results',
                                defaultMessage: 'Пользователь не найден',
                            })}
                        </div>
                    )}
                    {results.map((user) => (
                        <div
                            key={user.id}
                            className='user-multi-select__option'
                            onClick={() => handleSelect(user)}
                        >
                            <img
                                className='user-multi-select__avatar'
                                src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
                                alt={user.username}
                            />
                            <span className='user-multi-select__option-name'>
                                {user.username}
                            </span>
                            {(user.first_name || user.last_name) && (
                                <span className='user-multi-select__option-fullname'>
                                    {'— '}{`${user.first_name} ${user.last_name}`.trim()}
                                </span>
                            )}
                        </div>
                    ))}
                </div>
            )}
        </div>
    );
};

export default UserMultiSelect;
