import React, { useState, useEffect } from 'react';
import { isEmpty } from 'lodash-es';
import { useContractTermsByAccount } from 'src/apollo/queries/contract-term';
import {
    useProductSearch,
    useProductByUpc,
} from 'src/apollo/queries/product-search';
import SearchableSelectList from 'src/components/shared/searchable-select-list';
import { existingContractAttachments } from 'src/utils/contract';
import type { SearchProductsAbacusQuery } from 'src/apollo/queries/product-search/__generated__/get-products';

type Product = NonNullable<
    NonNullable<SearchProductsAbacusQuery['searchProducts']>['products']
>[0];

const SEARCH_PLACEHOLDER = 'Search for product(s)';

interface ProductSearchableSelectPropTypes {
    accountId: string;
    contractTermId: string;
    contractId: string;
    onChange: (params: any) => void;
    productUpcs: any;
    labelIds: any;
    setErrors: any;
}

const ProductSearchableSelect: React.FC<ProductSearchableSelectPropTypes> = ({
    accountId,
    contractTermId,
    contractId,
    onChange,
    productUpcs,
    labelIds,
    setErrors,
}) => {
    const selectName = 'productUpcs';
    const [searchTerm, setSearchTerm] = useState('');
    const [searchResults, setSearchResults] = useState<any>([]);
    const { data: contractTerms, getContractsTerms } =
        useContractTermsByAccount();
    const [productValues, setProductValues] = useState<any>([]);
    const { data: productData, getProductByUpc } = useProductByUpc();
    const [currentProductUpcs, setCurrentProductUpcs] = useState([]);
    const [areProductsLoaded, setAreProductsLoaded] = useState(false);
    const getPromisedProductSearch = useProductSearch();

    const performSearch = async (term: string) => {
        const trimmedTerm = term.trim().replace('\\', '');

        if (trimmedTerm) {
            setSearchTerm(trimmedTerm);
            const data = await getPromisedProductSearch(
                trimmedTerm,
                labelIds,
                100,
                0
            );
            const searchResults = data?.map((row: Product) => ({
                label: `${row.productName}-${row.upc}`,
                value: row.upc,
            }));
            setSearchResults(searchResults);
            return searchResults;
        }
    };

    const onBlur = () => {
        setErrors([]);
        if (!isEmpty(productValues))
            getContractsTerms(accountId, currentProductUpcs, 'product');
    };

    const onItemChange = (e: any) => {
        onChange({
            target: {
                name: selectName,
                value: e && e.map(({ value }: any) => value),
            },
        });
        setProductValues(e);
        setAreProductsLoaded(true);
    };

    useEffect(() => {
        if (isEmpty(productUpcs)) {
            setSearchResults([]);
            setSearchTerm('');
            setProductValues([]);
        } else setCurrentProductUpcs(productUpcs);
    }, [productUpcs]);

    useEffect(() => {
        if (!isEmpty(currentProductUpcs)) {
            const productUpc = currentProductUpcs[0];
            getProductByUpc(productUpc);
        }
    }, [currentProductUpcs]);

    useEffect(() => {
        if (productData && productData.productByUpc && !areProductsLoaded) {
            const row = productData.productByUpc;
            const item = {
                label: `${row.productName}-${row.upc}`,
                value: row.upc,
            };
            setSearchResults([...searchResults, item]);
            setProductValues([...productValues, item]);
            if (currentProductUpcs.length) {
                const newCurrentProductUpcs = currentProductUpcs.slice(1);
                if (newCurrentProductUpcs.length)
                    setCurrentProductUpcs([...newCurrentProductUpcs]);
                else setAreProductsLoaded(true);
            }
        }
    }, [productData]);

    useEffect(() => {
        if (!isEmpty(contractTerms)) {
            const terms = contractTerms?.abacusContractTermsByAccount;
            const otherContractTerms = terms?.filter(
                term => term.contract.contractId !== contractId
            );
            const { baseLevelAttachments, exceptionsAttachments }: any =
                existingContractAttachments(
                    contractTermId,
                    otherContractTerms,
                    currentProductUpcs
                );

            const messages: any = [];
            Object.keys(baseLevelAttachments).forEach(key =>
                messages.push(
                    `[${baseLevelAttachments[key]}] This product is already attached
                    to product-level contract ${key} for this account.
                    You must remove that product to create this product exception.`
                )
            );

            Object.keys(exceptionsAttachments).forEach(key =>
                messages.push(
                    `[${exceptionsAttachments[key]}] This product is already a
                    product exception on contract ${key} for this account.
                    You must remove that product exception to create this contract.`
                )
            );
            if (!isEmpty(messages)) setErrors(messages);
        }
    }, [contractTerms]);

    return (
        <SearchableSelectList
            className="product-select"
            clearable={true}
            defaultOptions={searchResults}
            isMultiSelect={true}
            id="productSearch"
            isLoading={false}
            onBlur={onBlur}
            onChange={onItemChange}
            onLoadOptionsHandler={performSearch}
            placeholder={SEARCH_PLACEHOLDER}
            searchTerm={searchTerm}
            value={productValues}
        />
    );
};

export default ProductSearchableSelect;
