import Zone from "@insite/client-framework/Components/Zone";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getCurrentAccountState } from "@insite/client-framework/Store/Data/Accounts/AccountsSelector";
import loadCurrentAccount from "@insite/client-framework/Store/Data/Accounts/Handlers/LoadCurrentAccount";
import {
    getReviewAndPayCartState,
    isCartLoadedWithoutLines,
} from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getCurrentCountries } from "@insite/client-framework/Store/Data/Countries/CountriesSelectors";
import { getCurrentPage, getQueryStrings } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { getReviewAndPayPromotions } from "@insite/client-framework/Store/Data/Promotions/PromotionsSelectors";
import loadDataIfNeeded from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/LoadDataIfNeeded";
import setCartId from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetCartId";
import setInitialValues from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetInitialValues";
import setPaymentDetailsState from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetPaymentDetailsState";
import PageModule from "@insite/client-framework/Types/PageModule";
import PageProps from "@insite/client-framework/Types/PageProps";
import LoadingOverlay from "@insite/mobius/LoadingOverlay";
import Page from "@insite/mobius/Page";
import React, { createContext, useEffect, useState } from "react";
import { connect, ResolveThunks } from "react-redux";

const mapStateToProps = (state: ApplicationState) => {
    const { cartId } = getQueryStrings(state);
    const cartState = getReviewAndPayCartState(state);
    const { paymentDetailsState } = state.pages.onePageCheckout;
    const promotionsDataView = getReviewAndPayPromotions(state);
    const location = getCurrentPage(state);
    const expand = state.data.carts.cartApiParameter?.expand || [];

    const isLoadDataNeeded =
        ((isCartLoadedWithoutLines(cartState) ||
            !cartState.value?.carriers ||
            !expand.includes("shipping") ||
            !expand.includes("tax")) &&
            !cartState.isLoading) ||
        (!promotionsDataView.value && !promotionsDataView.isLoading);

    return {
        cartId,
        cartState,
        isLoadDataNeeded: isLoadDataNeeded || !getCurrentCountries(state),
        isUpdatingCustomer: state.pages.onePageCheckout.isUpdatingCustomer,
        shouldLoadAccount: !getCurrentAccountState(state).value,
        location,
        paymentDetailsState,
    };
};

const mapDispatchToProps = {
    loadDataIfNeeded,
    setInitialValues,
    setCartId,
    loadCurrentAccount,
    setPaymentDetailsState,
};

type Props = PageProps & ResolveThunks<typeof mapDispatchToProps> & ReturnType<typeof mapStateToProps>;

type Validator = () => Promise<boolean>;

type State = {
    formSubmitAttempted: boolean;
    validators: {
        [key: string]: Validator | undefined;
    };
};

export const OnePageCheckoutFormContext = createContext<State>({
    formSubmitAttempted: false,
    validators: {},
});

const OnePageCheckoutPage = ({
    id,
    cartId,
    isLoadDataNeeded,
    isUpdatingCustomer,
    shouldLoadAccount,
    loadDataIfNeeded,
    setInitialValues,
    setCartId,
    loadCurrentAccount,
    location,
    paymentDetailsState,
    setPaymentDetailsState,
}: Props) => {
    const [state] = useState<State>({
        formSubmitAttempted: false,
        validators: {},
    });

    useEffect(() => {
        if (isLoadDataNeeded) {
            loadDataIfNeeded({ cartId, onSuccess: () => setInitialValues() });
        }
    });

    useEffect(() => {
        setCartId({ cartId });
        if (!isLoadDataNeeded) {
            setInitialValues();
        }
        if (shouldLoadAccount) {
            loadCurrentAccount();
        }
    }, []);

    useEffect(() => {
        if (paymentDetailsState === "complete") {
            setPaymentDetailsState({ paymentDetailsState: "active" });
        }
    }, [location]);

    return (
        <Page>
            <LoadingOverlay loading={isUpdatingCustomer}>
                <OnePageCheckoutFormContext.Provider value={state}>
                    <Zone zoneName="Content" contentId={id} />
                </OnePageCheckoutFormContext.Provider>
            </LoadingOverlay>
        </Page>
    );
};

const pageModule: PageModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(OnePageCheckoutPage),
    definition: {
        hasEditableUrlSegment: true,
        hasEditableTitle: true,
        pageType: "System",
    },
};

export default pageModule;
