import React from 'react';
import { useApolloClient } from '@apollo/client';
import { AsyncCreatableSelect as FRCAsyncCreatableSelect } from '@orchard/frontend-react-components';
import RSAsyncCreatableSelect from 'react-select/async-creatable';
import { Option as SelectOption } from 'react-select/src/filters';
import { formatMessage } from '@orchard/frontend-localization';
import { COLLABORATORS_SEARCH_QUERY } from 'src/queries/collaborator-search';
import { CollaboratorSearch, CollaboratorSearchVariables } from 'src/queries/__definitions__/CollaboratorSearch';
import { Collaborator } from 'src/types/SplitEditState';
import { formatCollaboratorName } from 'src/utils/formatters';
import messages from './i18n';

const AsyncSelect = FRCAsyncCreatableSelect as unknown as typeof RSAsyncCreatableSelect;

const CLASS_NAME = 'CollaboratorDropdown';

const addNewOption = { addNew: true };

type Option = Collaborator | typeof addNewOption;
export type Filter = (option: SelectOption, rawInput: string) => boolean;

type Props = {
    disabled: boolean;
    value: Collaborator | null;
    onChange(collaborator: Collaborator | null): void;
    onOpenAddCollaboratorModal(): void;
    filterOption?: Filter
};

const CollaboratorDropdown: React.FC<Props> = ({ disabled, value, onChange, onOpenAddCollaboratorModal, filterOption }) => {
    const client = useApolloClient();

    const loadOptions = async (searchTerm: string) => {
        const queryResult = await client.query<
        CollaboratorSearch,
        CollaboratorSearchVariables
        >({
            query: COLLABORATORS_SEARCH_QUERY,
            variables: { searchTerm },
        });

        return (queryResult.data.collaboratorSearch?.collaborators || []);
    };

    const handleCreateCollaborator = () => {
        onOpenAddCollaboratorModal();
    };

    return (
        <AsyncSelect
            className={ CLASS_NAME }
            disabled={ disabled }
            allowCreateWhileLoading
            cacheOptions
            defaultOptions={ [addNewOption] }
            getNewOptionData={ () => addNewOption as Option }
            // @ts-ignore returning a React node is valid but the types say it has to be a string
            getOptionLabel={ (option) =>
                !('addNew' in option)
                    ? (
                        formatCollaboratorName(option.name, option.collaboratorType)
                    )
                    : (
                        <span
                            className={ `${CLASS_NAME}-create-collaborator-option` }
                        >
                            + { formatMessage(messages.createCollaborator) }
                        </span>
                    )
            }
            getOptionValue={ (option) =>
                !('addNew' in option) ? option.id.toString() : 'add-new'
            }
            loadOptions={ loadOptions }
            isMulti={ false }
            isClearable
            onChange={ (option) => {
                if (option && 'addNew' in option) {
                    handleCreateCollaborator();
                    return;
                }
                onChange(option);
            } }
            value={ value }
            onCreateOption={ handleCreateCollaborator }
            placeholder={ formatMessage(messages.searchCollaborator) }
            filterOption={ filterOption }
        />
    );
};

export default CollaboratorDropdown;
