import React, { type FC, useCallback, useMemo, useState } from 'react';
import { Dropdown } from '@theorchard/suite-components';
import {
    useNrContributorSearchQuery,
    useGetAllNrContributors,
    useNrContributorByIdQuery,
} from 'src/data/queries';
import { useGetRegisteredContributors } from 'src/data/queries/getRegisteredContributors';
import { type NrContributorsSearch_nrContributorSearch_contributors as Contributor } from 'src/data/queries/nrContributorSearch/__generated__/NrContributorsSearch';
import { type DropdownOption, type SearchableDropdownOption } from 'src/types';
import { useDebounceCallback, type InputChangeCallback } from '../utils';

export const CLASSNAME = 'ContributorSearchDropdown';

export interface Props {
    disabled?: boolean;
    onChange: (data?: Contributor) => void;
    contributorId?: string;
    placeholder: string;
    defaultSelection?: Contributor | null;
    showEligible?: boolean;
    storeId?: string;
}

const createOption = (
    contributor: Contributor
): DropdownOption<Contributor> => ({
    label: contributor.name,
    value: contributor.id,
    data: contributor,
});

const ContributorsSearchDropdown: FC<Props> = props => {
    const {
        onChange,
        disabled,
        contributorId,
        placeholder,
        defaultSelection,
        showEligible,
        storeId,
    } = props;
    const [term, setTerm] = useState<string>();
    const [executeSearch, { data: searchData, loading }] =
        useNrContributorSearchQuery();
    const { data } = useGetAllNrContributors({ limit: 100 }, showEligible);

    const { data: eligibleContributors, loading: registeredLoading } =
        useGetRegisteredContributors({
            cmoId: showEligible && storeId ? storeId : '',
        });
    const sortedEligibleContributors = [...(eligibleContributors ?? [])].sort(
        (a, b) => a.name.localeCompare(b.name)
    );

    const listData = showEligible
        ? sortedEligibleContributors
        : data?.contributors;
    const dataSource: Contributor[] | null | undefined = term
        ? searchData
        : listData;
    const { data: contributorData } = useNrContributorByIdQuery({
        id: contributorId || '',
    });

    const handleInputChange = useDebounceCallback<InputChangeCallback>(
        (searchTerm: string, { action }) => {
            if (showEligible) return;
            setTerm(searchTerm);
            if (action !== 'menu-close')
                executeSearch({ variables: { term: searchTerm } });
        },
        300
    );

    const contributorOptions = useMemo<DropdownOption<Contributor>[]>(() => {
        const options = [...(dataSource ?? [])].map(createOption);
        return options;
    }, [dataSource]);

    const handleChange = useCallback(
        (newValue?: SearchableDropdownOption<Contributor>) => {
            onChange(newValue?.data);
        },
        [onChange]
    );

    let selectedOption: DropdownOption<Contributor> | null = null;
    if (defaultSelection) selectedOption = createOption(defaultSelection);
    else if (contributorData?.name)
        selectedOption = createOption(contributorData);

    const formattedOption = (option: DropdownOption<Contributor>) => (
        <div className={`${CLASSNAME}-option`}>
            <div className={`${CLASSNAME}-option-name`}>
                {option.data?.name}
            </div>
        </div>
    );

    const isLoading = showEligible ? registeredLoading : loading && !searchData;

    return (
        <Dropdown.Custom
            type="Select"
            name="contributorSearchDropdown"
            className={CLASSNAME}
            onChange={handleChange}
            onInputChange={handleInputChange}
            options={contributorOptions}
            isDisabled={disabled}
            value={selectedOption}
            formatOptionLabel={formattedOption}
            isLoading={isLoading}
            placeholder={placeholder}
            isClearable
            controlled
        />
    );
};

export default ContributorsSearchDropdown;
