import waitFor from "@insite/client-framework/Common/Utilities/waitFor";
import {
    createHandlerChainRunner,
    Handler,
    HasOnSuccess,
    markSkipOnCompleteIfOnSuccessIsSet,
} from "@insite/client-framework/HandlerCreator";
import { CartResult, getCart, GetCartApiParameter } from "@insite/client-framework/Services/CartService";
import { getCurrentPage } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { nullPage } from "@insite/client-framework/Store/Data/Pages/PagesState";
import loadPromotions from "@insite/client-framework/Store/Data/Promotions/Handlers/LoadPromotions";
import { getPromotionsDataView } from "@insite/client-framework/Store/Data/Promotions/PromotionsSelectors";

type HandlerType = Handler<
    | ({
          cartId: string;
          shouldLoadFullCart?: boolean;
          getPromotions?: boolean;
      } & HasOnSuccess)
    | ({
          apiParameter: GetCartApiParameter;
      } & HasOnSuccess),
    {
        apiParameter: GetCartApiParameter;
        apiResult: CartResult;
        needFullCart: boolean;
    }
>;
export const DispatchBeginLoadCart: HandlerType = async props => {
    props.dispatch({
        type: "Data/Carts/BeginLoadCart",
        id: "cartId" in props.parameter ? props.parameter.cartId : props.parameter.apiParameter.cartId,
    });

    await waitFor(() => getCurrentPage(props.getState()) !== nullPage);
};

export const SetNeedFullCart: HandlerType = props => {
    if (!("cartId" in props.parameter)) {
        return;
    }

    const pageType = getCurrentPage(props.getState()).type;
    props.needFullCart =
        props.parameter.shouldLoadFullCart ||
        pageType === "OnePageCheckoutPage" ||
        pageType === "OnePageCheckoutConfirmationPage" ||
        pageType === "CheckoutShippingPage" ||
        pageType === "CheckoutReviewAndSubmitPage" ||
        pageType === "OrderConfirmationPage";
};

export const PopulateApiParameter: HandlerType = props => {
    if ("apiParameter" in props.parameter) {
        props.apiParameter = props.parameter.apiParameter;
        return;
    }

    props.apiParameter = {
        cartId: props.parameter.cartId,
        expand: ["validation"],
    };

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

export const GetCart: HandlerType = async props => {
    try {
        props.apiResult = await getCart(props.apiParameter);
    } catch (error) {
        if ("status" in error && (error.status === 404 || error.status === 403)) {
            props.dispatch({
                type: "Data/Carts/FailedToLoadCart",
                cartId: props.apiParameter.cartId,
                status: error.status,
            });
            return false;
        }
        throw error;
    }
};

export const DispatchCompleteLoadCart: HandlerType = props => {
    props.dispatch({
        type: "Data/Carts/CompleteLoadCart",
        model: props.apiResult.cart,
    });
};

export const DispatchCompleteLoadBillTo: HandlerType = props => {
    if (!props.apiResult.billTo) {
        return;
    }

    props.dispatch({
        type: "Data/BillTos/CompleteLoadBillTo",
        model: props.apiResult.billTo,
    });
};

export const DispatchCompleteLoadShipTo: HandlerType = props => {
    if (!props.apiResult.shipTo) {
        return;
    }

    props.dispatch({
        type: "Data/ShipTos/CompleteLoadShipTo",
        model: props.apiResult.shipTo,
    });
};

export const DispatchLoadPromotions: HandlerType = props => {
    if (!("cartId" in props.parameter)) {
        return;
    }

    const promotionsState = getPromotionsDataView(props.getState(), props.parameter.cartId);
    const promotionsNotLoaded = !promotionsState.value && !promotionsState.isLoading;
    if (
        props.parameter.getPromotions ||
        props.parameter.shouldLoadFullCart ||
        (props.needFullCart && promotionsNotLoaded)
    ) {
        props.dispatch(loadPromotions({ cartId: props.parameter.cartId }));
    }
};

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

export const chain = [
    DispatchBeginLoadCart,
    SetNeedFullCart,
    PopulateApiParameter,
    GetCart,
    DispatchCompleteLoadCart,
    DispatchCompleteLoadBillTo,
    DispatchCompleteLoadShipTo,
    DispatchLoadPromotions,
    ExecuteOnSuccessCallback,
];

const loadCart = createHandlerChainRunner(chain, "LoadCart");
export default loadCart;
