import { ProductInfo } from "@insite/client-framework/Common/ProductInfo";
import { SafeDictionary } from "@insite/client-framework/Common/Types";
import waitFor from "@insite/client-framework/Common/Utilities/waitFor";
import { getIsWebCrawler } from "@insite/client-framework/Common/WebCrawler";
import { createHandlerChainRunner, Handler, makeHandlerChainAwaitable } from "@insite/client-framework/HandlerCreator";
import loadRealTimeInventory from "@insite/client-framework/Store/CommonHandlers/LoadRealTimeInventory";
import loadRealTimePricing from "@insite/client-framework/Store/CommonHandlers/LoadRealTimePricing";
import { getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import { ProductModel, RealTimePricingModel } from "@insite/client-framework/Types/ApiModels";

interface Parameter {
    products?: ProductModel[];
    productInfosByProductId: SafeDictionary<ProductInfo>;
}

export interface DisplayProductsResult {}

interface Props {
    pricingLoaded: boolean;
}

type HandlerType = Handler<Parameter, Props>;

export const LoadRealTimePrices: HandlerType = async props => {
    const { productInfosByProductId } = props.parameter;

    const productIds = Object.keys(productInfosByProductId).filter(o => !productInfosByProductId[o]?.pricing);
    if (productIds.length === 0) {
        return;
    }

    const loadRealTimePricingParameter: Parameters<typeof loadRealTimePricing>[0] = {
        productPriceParameters: productIds.map(o => productInfosByProductId[o]!),
        onSuccess: realTimePricing => {
            props.dispatch({
                type: "Pages/ProductList/CompleteLoadRealTimePricing",
                realTimePricing,
            });
            props.pricingLoaded = true;
        },
        onError: () => {
            props.dispatch({
                type: "Pages/ProductList/FailedLoadRealTimePricing",
            });
            props.pricingLoaded = true;
        },
        onComplete(realTimePricingProps) {
            if (realTimePricingProps.apiResult) {
                this.onSuccess?.(realTimePricingProps.apiResult);
            } else if (realTimePricingProps.error) {
                this.onError?.(realTimePricingProps.error);
            }
        },
    };

    const settings = getSettingsCollection(props.getState());

    if (IS_SERVER_SIDE && getIsWebCrawler() && !settings.websiteSettings.includeRealTimeInventoryAndPricingForSeo) {
        const awaitableLoadRealTimePricing = makeHandlerChainAwaitable<
            Parameters<typeof loadRealTimePricing>[0],
            RealTimePricingModel
        >(loadRealTimePricing);
        const realTimePricing = await awaitableLoadRealTimePricing({
            productPriceParameters: loadRealTimePricingParameter.productPriceParameters,
        })(props.dispatch, props.getState);
        if (realTimePricing) {
            loadRealTimePricingParameter.onSuccess?.(realTimePricing);
        } else {
            loadRealTimePricingParameter.onError?.(realTimePricing);
        }
    } else {
        props.dispatch(loadRealTimePricing(loadRealTimePricingParameter));
    }

    const productSettings = settings.productSettings;
    if (productSettings.canSeePrices && productSettings.inventoryIncludedWithPricing) {
        await waitFor(() => !!props.pricingLoaded);
    }
};

export const LoadRealTimeInventory: HandlerType = props => {
    if (
        !props.parameter.products?.length ||
        (getIsWebCrawler() &&
            !getSettingsCollection(props.getState()).websiteSettings.includeRealTimeInventoryAndPricingForSeo)
    ) {
        return;
    }

    const { productInfosByProductId } = props.parameter;

    const productIds = Object.keys(productInfosByProductId).filter(o => !productInfosByProductId[o]?.inventory);
    if (productIds.length === 0) {
        return;
    }

    props.dispatch(
        loadRealTimeInventory({
            productIds,
            onSuccess: realTimeInventory => {
                props.dispatch({
                    type: "Pages/ProductList/CompleteLoadRealTimeInventory",
                    realTimeInventory,
                });
            },
            onError: () => {
                props.dispatch({
                    type: "Pages/ProductList/FailedLoadRealTimeInventory",
                });
            },
            onComplete(realTimeInventoryProps) {
                if (realTimeInventoryProps.apiResult) {
                    this.onSuccess?.(realTimeInventoryProps.apiResult);
                } else if (realTimeInventoryProps.error) {
                    this.onError?.(realTimeInventoryProps.error);
                }
            },
        }),
    );
};
export const chain = [LoadRealTimePrices, LoadRealTimeInventory];

const loadProductsPricingAndInventory = createHandlerChainRunner(chain, "LoadProductsPricingAndInventory");
export default loadProductsPricingAndInventory;
