import waitFor from "@insite/client-framework/Common/Utilities/waitFor";
import {
    createHandlerChainRunnerOptionalParameter,
    Handler,
    HasOnSuccess,
} from "@insite/client-framework/HandlerCreator";
import { API_URL_CURRENT_FRAGMENT } from "@insite/client-framework/Services/ApiService";
import { CartResult, getCart, GetCartApiParameter } from "@insite/client-framework/Services/CartService";
import prepareCart from "@insite/client-framework/Store/Components/ProductRecommendations/Handlers/PrepareCart";
import { getSession } from "@insite/client-framework/Store/Context/ContextSelectors";
import { getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getCurrentPage } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { nullPage } from "@insite/client-framework/Store/Data/Pages/PagesState";
import loadCurrentPromotions from "@insite/client-framework/Store/Data/Promotions/Handlers/LoadCurrentPromotions";
import { getCurrentPromotionsDataView } from "@insite/client-framework/Store/Data/Promotions/PromotionsSelectors";

type HandlerType = Handler<
    {
        shouldLoadFullCart?: boolean;
        replaceCart?: boolean;
        getPromotions?: boolean;
        getCartLines?: boolean;
        getCostCodes?: boolean;
    } & HasOnSuccess,
    {
        apiParameter: GetCartApiParameter;
        apiResult: CartResult;
        needFullCart: boolean;
    }
>;

export const DispatchBeginLoadCart: HandlerType = async props => {
    const state = props.getState();
    if (getCurrentCartState(state).isLoading) {
        return false;
    }

    props.dispatch({
        type: "Data/Carts/BeginLoadCart",
        id: API_URL_CURRENT_FRAGMENT,
    });

    if (props.parameter.shouldLoadFullCart !== false) {
        await waitFor(() => getCurrentPage(props.getState()) !== nullPage);
    }
};

export const SetNeedFullCart: HandlerType = props => {
    const pageType = getCurrentPage(props.getState()).type;
    props.needFullCart =
        props.parameter.shouldLoadFullCart ||
        (props.parameter.shouldLoadFullCart !== false &&
            (pageType === "CheckoutShippingPage" ||
                pageType === "CheckoutReviewAndSubmitPage" ||
                pageType === "CartPage" ||
                pageType === "OnePageCheckoutPage" ||
                pageType === "RfqRequestQuotePage"));
};

export const PopulateApiParameter: HandlerType = props => {
    const pageType = getCurrentPage(props.getState()).type;
    props.apiParameter = {
        cartId: API_URL_CURRENT_FRAGMENT,
        expand: ["shipping"],
    };

    if (!getSession(props.getState()).rememberMe) {
        props.apiParameter.expand?.push("validation");
    }

    if (props.needFullCart) {
        props.apiParameter.forceRecalculation = true;
        props.apiParameter.allowInvalidAddress = true;
        props.apiParameter.expand = [
            ...(props.apiParameter.expand || []),
            "cartLines",
            "restrictions",
            "tax",
            "carriers",
            "paymentOptions",
            "costCodes",
        ];

        if (pageType === "CartPage") {
            props.apiParameter.expand.push("hiddenproducts");
        }
    }

    if (props.parameter.getCartLines) {
        props.apiParameter.expand?.push("cartLines");
    }

    if (props.parameter.getCostCodes) {
        props.apiParameter.expand?.push("costCodes");
    }
};

export const GetCart: HandlerType = async props => {
    props.apiResult = await getCart(props.apiParameter);
};

export const SetCarrier: HandlerType = props => {
    const { carrier, carriers } = props.apiResult.cart;
    if (carriers) {
        const carrierLookup = carriers.find(c => c.id === carrier?.id);
        if (carrierLookup) {
            props.apiResult.cart.carrier = carrierLookup;
        }
    }
};

export const PrepareCart: HandlerType = ({ getState, dispatch, apiResult: { cart } }) => {
    const pageType = getCurrentPage(getState()).type;
    if (pageType === "CartPage") {
        dispatch(prepareCart({ cart }));
    }
};

export const DispatchCompleteLoadCart: HandlerType = props => {
    let replaceCart = !props.needFullCart;
    if (typeof props.parameter.replaceCart !== "undefined") {
        replaceCart = props.parameter.replaceCart;
    }

    props.dispatch({
        type: "Data/Carts/CompleteLoadCart",
        model: props.apiResult.cart,
        isCurrent: true,
        replaceCart,
    });
};

export const DispatchLoadCustomers: HandlerType = props => {
    if (props.apiResult.billTo) {
        delete props.apiResult.billTo.accountsReceivable;
        delete props.apiResult.billTo.costCodes;
        props.dispatch({
            type: "Data/BillTos/CompleteLoadBillTo",
            model: props.apiResult.billTo,
        });
    }
    if (props.apiResult.shipTo) {
        props.dispatch({
            type: "Data/ShipTos/CompleteLoadShipTo",
            model: props.apiResult.shipTo,
        });
    }
};

export const DispatchLoadPromotions: HandlerType = props => {
    const currentPromotionsState = getCurrentPromotionsDataView(props.getState());
    const promotionsNotLoaded = !currentPromotionsState.value && !currentPromotionsState.isLoading;
    if (
        props.parameter.getPromotions ||
        props.parameter.shouldLoadFullCart ||
        (props.needFullCart && promotionsNotLoaded)
    ) {
        props.dispatch(loadCurrentPromotions());
    }
};

export const ExecuteOnSuccessCallback: HandlerType = props => {
    props.parameter.onSuccess?.();
};

export const chain = [
    DispatchBeginLoadCart,
    SetNeedFullCart,
    PopulateApiParameter,
    GetCart,
    SetCarrier,
    PrepareCart,
    DispatchCompleteLoadCart,
    DispatchLoadCustomers,
    DispatchLoadPromotions,
    ExecuteOnSuccessCallback,
];

const loadCurrentCart = createHandlerChainRunnerOptionalParameter(chain, {}, "LoadCurrentCart");
export default loadCurrentCart;
