import type { FC } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useApolloClient } from '@apollo/client';
import { SearchDropdown, Field } from '@theorchard/suite-components';
import { formatMessage } from '@theorchard/suite-frontend';
import {
    getPromisedLabelSearch,
    useOrchardLabelByIdQuery,
    useOrchardLabels,
} from 'src/data/queries';
import type { OrchardLabelSearchQuery } from 'src/data/queries/orchardLabelSearch/__generated__/orchardLabelSearch';
import type {
    DropdownOption,
    Label,
    SearchableDropdownOption,
} from 'src/types';

type OrchardLabelSearch = OrchardLabelSearchQuery['orchardLabelSearch'][0];

export const CLASSNAME = 'LabelSearchDropdown';

export interface Props {
    unwrap?: boolean;
    disabled?: boolean;
    onChange: (data?: OrchardLabelSearch) => void;
    vendorId?: number;
    formatOptionLabel?: (
        option: DropdownOption<OrchardLabelSearch>
    ) => JSX.Element;
    errorMessage?: string;
}

export const getOptionName = (label: OrchardLabelSearch) =>
    `${label.name} - ${label.uuid} - ${label.id.vendorId}`;

const createOption = (
    label: OrchardLabelSearch
): DropdownOption<OrchardLabelSearch> => ({
    label: getOptionName(label),
    value: label.uuid,
    data: label,
});

const LabelSearchDropdown: FC<Props> = ({
    onChange,
    unwrap,
    disabled,
    vendorId,
    formatOptionLabel,
    errorMessage,
}) => {
    const apolloClient = useApolloClient();
    const { data: listData } = useOrchardLabels();
    // our vendors won't have subaccountIds so can just set this to 0.
    const variables = { id: { subaccountId: 0, vendorId } };
    const { data: selectedLabel } = useOrchardLabelByIdQuery(variables);

    const handleInputChange = async (searchTerm: string) => {
        const data = await getPromisedLabelSearch(searchTerm, apolloClient);

        return data.map(createOption);
    };

    const labelOptions = useMemo<DropdownOption<OrchardLabelSearch>[]>(
        () => [...(listData ?? [])].map(createOption),
        [listData]
    );

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

    const handleSingleLabel = useCallback(
        (newValue?: Label) => {
            onChange(newValue);
        },
        [onChange]
    );

    useEffect(() => {
        if (listData?.length === 1 && listData[0].id.vendorId !== vendorId)
            handleSingleLabel(listData[0]);
    }, [vendorId, listData, handleSingleLabel]);

    let selectedOption: DropdownOption<OrchardLabelSearch> | null = null;
    if (selectedLabel?.name)
        selectedOption = createOption({
            id: {
                vendorId: selectedLabel.id.vendorId,
                subaccountId: 0,
            },
            name: selectedLabel.name,
            uuid: selectedLabel.uuid,
        });

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

    const renderDropDown = () => (
        <SearchDropdown
            name="labelSearchDropdown"
            className={CLASSNAME}
            onChange={handleChange}
            onLoadOptions={handleInputChange}
            defaultOptions={labelOptions}
            isDisabled={disabled}
            value={selectedOption}
            formatOptionLabel={formatOptionLabel || formattedOption}
            placeholder={formatMessage('generic.searchForLabel')}
            debounceTime={300}
        />
    );

    if (listData?.length === 1) return <div className={`${CLASSNAME} hide`} />;

    if (unwrap) return renderDropDown();

    return (
        <Field
            controlId="labelAsyncSelect"
            labelText={formatMessage('generic.labelAccount')}
            errorMessage={errorMessage}
        >
            {renderDropDown()}
        </Field>
    );
};

export default LabelSearchDropdown;
