
import { useEffect, useState, useCallback } from 'react';

export const useDomainSuggestions = (
    endpointConfig,
    fetchSuggestions,
    genericErrorMessage,
    noResultErrorMessage
) => {
    const [suggestions, setSuggestions] = useState([]);
    const [isLoading, setIsLoading] = useState(false);
    const [statusMessage, setStatusMessage] = useState(null);
    const [isError, setIsError] = useState(false);
    const [isWarning, setIsWarning] = useState(false);
    const [searchValue, setSearchValue] = useState(null);

    const dismissMessage = () => {
        setIsError(false);
        setIsWarning(false);
    };

    const finalSuggestionFetch = useCallback(params => {
        if (fetchSuggestions) {
            return fetchSuggestions(params);
        }
        const { endpoint, options } = endpointConfig;
        if (!endpoint) {
            return Promise.resolve(null);
        }
        const parsedOptions = Object.keys(options).reduce((builtParams, paramName) => {
            const paramValue = params[paramName] || options[paramName];
            return [
                ...builtParams,
                `${paramName}=${paramValue}`
            ];
        }, []).join('&');
        const finalEndpoint = `${endpoint}?${parsedOptions}`;
        return fetch(finalEndpoint).then(res => {
            if (res.status === 400) {
                return Promise.resolve(null);
            }
            return res.json();
        });
    }, [endpointConfig, fetchSuggestions]);

    // perform ajax fetch whenever we click on search and thus change de search value.
    useEffect(
        () => {
            if (!searchValue) {
                setSuggestions([]);
                return undefined;
            }

            // keep a closure var to invalidate all effects of this call when a subsequent
            // call is made, or component unmounts
            let isCancelled = false;
            setIsLoading(true);
            const onResolved = finalSuggestionFetch({ q: searchValue });
            onResolved.then(result => {
                // this effect has been invalidated, do nothing
                if (isCancelled) {
                    return;
                }
                setIsLoading(false);
                setSuggestions(result);
                if (!result || !result.length) {
                    setStatusMessage(noResultErrorMessage);
                    setIsWarning(true);
                }
            }).catch(() => {
                if (isCancelled) {
                    return;
                }
                setIsLoading(false);
                setStatusMessage(genericErrorMessage);
                setIsError(true);
            });
            return () => {
                isCancelled = true;
            };
        },
        [searchValue, finalSuggestionFetch]
    );

    return {
        suggestions,
        isLoading,
        setSearchValue,
        isError,
        isWarning,
        statusMessage,
        dismissMessage
    };
};
