import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import setAddressBookOverlayIsOpen from "@insite/client-framework/Store/Components/AddressBookOverlay/Handlers/SetAddressBookOverlayIsOpen";
import { getAddressFieldsDataView } from "@insite/client-framework/Store/Data/AddressFields/AddressFieldsSelector";
import { getBillToState } from "@insite/client-framework/Store/Data/BillTos/BillTosSelectors";
import { getCartState, getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getCurrentCountries } from "@insite/client-framework/Store/Data/Countries/CountriesSelectors";
import { getCurrentPage } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { getShipTosDataView, getShipToState } from "@insite/client-framework/Store/Data/ShipTos/ShipTosSelectors";
import { getPageLinkByPageType } from "@insite/client-framework/Store/Links/LinksSelectors";
import updateCheckoutShippingBillTo from "@insite/client-framework/Store/Pages/CheckoutShipping/Handlers/UpdateBillTo";
import updateCheckoutShippingShipTo from "@insite/client-framework/Store/Pages/CheckoutShipping/Handlers/UpdateShipTo";
import updateOnePageCheckoutBillTo from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/UpdateBillTo";
import updateOnePageCheckoutShipTo from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/UpdateShipTo";
import translate from "@insite/client-framework/Translate";
import { BaseAddressModel, BillToModel, ShipToModel } from "@insite/client-framework/Types/ApiModels";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import BillToSelector, { BillToSelectorStyles } from "@insite/content-library/Components/BillToSelector";
import CustomerAddressForm, { CustomerAddressFormStyles } from "@insite/content-library/Components/CustomerAddressForm";
import ShipToSelector, { ShipToSelectorStyles } from "@insite/content-library/Components/ShipToSelector";
import { HasToasterContext, withToaster } from "@insite/mobius/Toast/ToasterContext";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import breakpointMediaQueries from "@insite/mobius/utilities/breakpointMediaQueries";
import { HasHistory, withHistory } from "@insite/mobius/utilities/HistoryContext";
import * as React from "react";
import { useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const cartId = state.pages.checkoutShipping.cartId;
    const cart = cartId ? getCartState(state, cartId).value : getCurrentCartState(state).value;
    const page = getCurrentPage(state);
    const isCheckoutShippingPage = page.type === "CheckoutShippingPage";
    const isOnePageCheckoutPage = page.type === "OnePageCheckoutPage";
    return {
        isBillTo: state.components.addressBookOverlay.isBillTo,
        useOneTimeAddress: state.pages.checkoutShipping.useOneTimeAddress,
        shippingAddressFormState:
            page.type === "CheckoutShippingPage"
                ? state.pages.checkoutShipping.shippingAddressFormState
                : page.type === "OnePageCheckoutPage"
                ? state.pages.onePageCheckout.shippingAddressFormState
                : undefined,
        cartPageUrl: getPageLinkByPageType(state, "CartPage")?.url,
        countries: getCurrentCountries(state),
        shipToAddressFields: getAddressFieldsDataView(state).value?.shipToAddressFields,
        billToAddressFields: getAddressFieldsDataView(state).value?.billToAddressFields,
        cart,
        cartBillTo: getBillToState(state, cart?.billToId)?.value,
        currentShipTo: getShipToState(state, cart ? cart.shipToId : undefined).value,
        shipTosDataView: cart
            ? getShipTosDataView(state, { billToId: cart.billToId, expand: ["validation"], exclude: ["showAll"] })
            : undefined,
        isCheckoutShippingPage,
        isOnePageCheckoutPage,
    };
};

const mapDispatchToProps = {
    setAddressBookOverlayIsOpen,
    updateCheckoutShippingBillTo,
    updateCheckoutShippingShipTo,
    updateOnePageCheckoutBillTo,
    updateOnePageCheckoutShipTo,
};

type Props = WidgetProps &
    ReturnType<typeof mapStateToProps> &
    ResolveThunks<typeof mapDispatchToProps> &
    HasHistory &
    HasToasterContext;

export interface AddressBookStyles {
    titleText?: TypographyPresentationProps;
    billToSelector?: BillToSelectorStyles;
    shipToSelector?: ShipToSelectorStyles;
    editCustomerAddressForm?: CustomerAddressFormStyles;
    addCustomerAddressForm?: CustomerAddressFormStyles;
}

export const addressBookStyles: AddressBookStyles = {
    titleText: { variant: "h5" },
    billToSelector: {
        customerSelectorToolbar: {
            wrapper: {
                css: css`
                    flex-direction: column;
                    gap: 10px;
                `,
            },
            searchTextField: {
                cssOverrides: {
                    formField: css`
                        flex-basis: 100%;
                        margin-bottom: 5px;
                    `,
                },
            },
        },
        customerSelector: {
            customerCard: {
                addressGridItem: { width: 10 },
                address: {
                    customerNameText: {
                        css: css`
                            font-weight: bold;
                        `,
                    },
                },
                editGridItem: { width: 2 },
                editLink: {
                    css: css`
                        align-items: flex-start;
                    `,
                },
                actionsGridItem: { width: 12 },
                actionsWrapper: {
                    css: css`
                        width: 100%;
                    `,
                },
                selectButton: {
                    css: css`
                        width: 100%;
                    `,
                },
            },
            customerCardSelected: {
                addressGridItem: { width: 10 },
                address: {
                    customerNameText: {
                        css: css`
                            font-weight: bold;
                        `,
                    },
                },
                editGridItem: { width: 2 },
                editLink: {
                    css: css`
                        align-items: flex-start;
                    `,
                },
                actionsGridItem: { width: 12 },
                actionsWrapper: {
                    css: css`
                        width: 100%;
                    `,
                },
                selectButton: {
                    css: css`
                        width: 100%;
                    `,
                },
            },
            pagination: {
                cssOverrides: {
                    perPageSelect: css`
                        margin-bottom: 10px;
                    `,
                },
            },
        },
    },
    shipToSelector: {
        customerSelectorToolbar: {
            wrapper: {
                css: css`
                    flex-direction: row-reverse;
                    flex-wrap: wrap;
                    gap: 10px;
                `,
            },
            searchTextField: {
                cssOverrides: {
                    formField: css`
                        flex-basis: 100%;
                        margin-bottom: 5px;
                    `,
                },
            },
            wideCreateNewAddressButton: {
                css: css`
                    margin-left: 0;
                    padding: 0 22px;
                `,
                variant: "secondary",
            },
        },
        customerSelector: {
            customerCard: {
                addressGridItem: { width: 10 },
                address: {
                    customerNameText: {
                        css: css`
                            font-weight: bold;
                        `,
                    },
                },
                editGridItem: { width: 2 },
                editLink: {
                    css: css`
                        align-items: flex-start;
                    `,
                },
                actionsGridItem: { width: 12 },
                actionsWrapper: {
                    css: css`
                        width: 100%;
                    `,
                },
                selectButton: {
                    css: css`
                        width: 100%;
                    `,
                },
            },
            customerCardSelected: {
                addressGridItem: { width: 10 },
                address: {
                    customerNameText: {
                        css: css`
                            font-weight: bold;
                        `,
                    },
                },
                editGridItem: { width: 2 },
                editLink: {
                    css: css`
                        align-items: flex-start;
                    `,
                },
                actionsGridItem: { width: 12 },
                actionsWrapper: {
                    css: css`
                        width: 100%;
                    `,
                },
                selectButton: {
                    css: css`
                        width: 100%;
                    `,
                },
            },
            pagination: {
                cssOverrides: {
                    perPageSelect: css`
                        margin-bottom: 10px;
                    `,
                    arrowButtons: css`
                        ${({ theme }) =>
                            breakpointMediaQueries(
                                theme,
                                [
                                    css`
                                        width: 24px;
                                    `,
                                    null,
                                    null,
                                    css`
                                        width: 37px;
                                    `,
                                    null,
                                ],
                                "min",
                            )};
                    `,
                },
            },
        },
    },
    editCustomerAddressForm: {
        formFields: {
            firstNameGridItem: { width: 12 },
            lastNameGridItem: { width: 12 },
            companyNameGridItem: { width: 12 },
            attentionGridItem: { width: 12 },
            stateGridItem: { width: 12 },
            postalCodeGridItem: { width: 12 },
            phoneGridItem: { width: 12 },
        },
        formButtonsWrapper: {
            css: css`
                margin-bottom: 20px;
            `,
        },
        cancelButton: {
            variant: "secondary",
        },
    },
    addCustomerAddressForm: {
        formFields: {
            firstNameGridItem: { width: 12 },
            lastNameGridItem: { width: 12 },
            companyNameGridItem: { width: 12 },
            attentionGridItem: { width: 12 },
            stateGridItem: { width: 12 },
            postalCodeGridItem: { width: 12 },
            phoneGridItem: { width: 12 },
        },
        formButtonsWrapper: {
            css: css`
                margin-bottom: 20px;
            `,
        },
        cancelButton: {
            variant: "secondary",
        },
    },
};

const styles = addressBookStyles;

const AddressBook = ({
    isBillTo,
    useOneTimeAddress,
    shippingAddressFormState,
    cartPageUrl,
    countries,
    shipToAddressFields,
    billToAddressFields,
    cart,
    cartBillTo,
    currentShipTo,
    shipTosDataView,
    isCheckoutShippingPage,
    isOnePageCheckoutPage,
    history,
    toaster,
    setAddressBookOverlayIsOpen,
    updateCheckoutShippingBillTo,
    updateCheckoutShippingShipTo,
    updateOnePageCheckoutBillTo,
    updateOnePageCheckoutShipTo,
}: Props) => {
    const [isShipToCreating, setIsShipToCreating] = useState(false);
    const [shiToBeingEdited, setShipToBeingEdited] = useState<ShipToModel | undefined>(undefined);
    const [billToBeingEdited, setBillToBeingEdited] = useState<BillToModel | undefined>(undefined);
    const updateBillTo = isCheckoutShippingPage
        ? updateCheckoutShippingBillTo
        : isOnePageCheckoutPage
        ? updateOnePageCheckoutBillTo
        : undefined;
    const updateShipTo = isCheckoutShippingPage
        ? updateCheckoutShippingShipTo
        : isOnePageCheckoutPage
        ? updateOnePageCheckoutShipTo
        : undefined;

    let newAddress;
    if (cart && cart.cartLines && shipTosDataView && shipTosDataView.value) {
        newAddress = shipTosDataView.value!.find(s => s.isNew && !s.oneTimeAddress);
    }

    const closeAddressBookOverlay = () => setAddressBookOverlayIsOpen({ isOpen: false });

    const selectBillToHandler = (billTo: BillToModel) => {
        closeAddressBookOverlay();
        updateBillTo &&
            updateBillTo({
                billTo,
                isEdit: false,
                onSuccess: hasCartlines => {
                    if (!hasCartlines && cartPageUrl) {
                        history.push(cartPageUrl);
                    }
                },
            });
    };

    const selectShipToHandler = (shipTo: ShipToModel) => {
        closeAddressBookOverlay();
        updateShipTo &&
            updateShipTo({
                billToId: cart?.billToId || "",
                shipTo,
                isEdit: false,
                onSuccess: hasCartlines => {
                    if (!hasCartlines && cartPageUrl) {
                        history.push(cartPageUrl);
                    }
                },
            });
    };

    const editBillToHandler = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, billTo: BillToModel) => {
        event.preventDefault();
        setBillToBeingEdited(billTo);
    };

    const editShipToHandler = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, customer: BaseAddressModel) => {
        event.preventDefault();
        setShipToBeingEdited(customer as ShipToModel);
    };

    const editAddressCancelHandler = () => {
        setShipToBeingEdited(undefined);
        setBillToBeingEdited(undefined);
    };

    const createNewAddressHandler = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
        event.preventDefault();
        setIsShipToCreating(true);
    };

    const createNewAddressCancelHandler = () => {
        setIsShipToCreating(false);
    };

    const editBillToFormSubmitHandler = (_: React.FormEvent<HTMLFormElement>, billTo: BillToModel) => {
        updateBillTo &&
            updateBillTo({
                billTo,
                isEdit: true,
                onSuccess: hasCartlines => {
                    toaster.addToast({
                        messageType: "success",
                        body: translate("Address updated."),
                    });
                    if (!hasCartlines && cartPageUrl) {
                        history.push(cartPageUrl);
                    }
                },
            });
        editAddressCancelHandler();
        closeAddressBookOverlay();
    };

    const editShipToFormSubmitHandler = (_: React.FormEvent<HTMLFormElement>, shipTo: ShipToModel) => {
        updateShipTo &&
            updateShipTo({
                billToId: cart?.billToId || "",
                shipTo,
                isEdit: true,
                onSuccess: hasCartlines => {
                    toaster.addToast({
                        messageType: "success",
                        body: translate("Address updated."),
                    });
                    if (!hasCartlines && cartPageUrl) {
                        history.push(cartPageUrl);
                    }
                },
            });
        editAddressCancelHandler();
        closeAddressBookOverlay();
    };

    const newShippingAddressFormSubmitHandler = (_: React.FormEvent<HTMLFormElement>, address: ShipToModel) => {
        updateShipTo &&
            updateShipTo({
                billToId: cart?.billToId || "",
                shipTo: address,
                isEdit: true,
                onSuccess: hasCartlines => {
                    toaster.addToast({
                        messageType: "success",
                        body: translate("Address has been created."),
                    });
                    if (!hasCartlines && cartPageUrl) {
                        history.push(cartPageUrl);
                    }
                },
            });

        setIsShipToCreating(false);
        closeAddressBookOverlay();
    };

    return (
        <>
            <Typography as="h2" {...styles.titleText}>
                {isShipToCreating
                    ? translate("New Address")
                    : billToBeingEdited || shiToBeingEdited
                    ? translate("Edit Address")
                    : translate("Address Book")}
            </Typography>
            {isBillTo && !billToBeingEdited && (
                <BillToSelector
                    onSelect={selectBillToHandler}
                    onEdit={editBillToHandler}
                    currentBillTo={cartBillTo}
                    extendedStyles={styles.billToSelector}
                    isOverlay={true}
                />
            )}
            {!isBillTo && !shiToBeingEdited && !isShipToCreating && (
                <ShipToSelector
                    currentShipTo={useOneTimeAddress && shippingAddressFormState ? undefined : currentShipTo}
                    currentBillToId={cart?.billToId}
                    newAddress={newAddress}
                    onSelect={selectShipToHandler}
                    onEdit={editShipToHandler}
                    onCreateNewAddressClick={newAddress && createNewAddressHandler}
                    extendedStyles={styles.shipToSelector}
                    isOverlay={true}
                />
            )}
            {billToBeingEdited && countries && billToAddressFields && (
                <CustomerAddressForm
                    address={billToBeingEdited}
                    countries={countries}
                    addressFieldDisplayCollection={billToAddressFields}
                    onSubmit={editBillToFormSubmitHandler}
                    saveButtonTextOverride={translate("Save & Apply")}
                    onCancel={editAddressCancelHandler}
                    extendedStyles={styles.editCustomerAddressForm}
                />
            )}
            {shiToBeingEdited && countries && shipToAddressFields && (
                <CustomerAddressForm
                    address={shiToBeingEdited}
                    countries={countries}
                    addressFieldDisplayCollection={shipToAddressFields}
                    onSubmit={editShipToFormSubmitHandler}
                    saveButtonTextOverride={translate("Save & Apply")}
                    onCancel={editAddressCancelHandler}
                    extendedStyles={styles.editCustomerAddressForm}
                />
            )}
            {isShipToCreating && newAddress && countries && shipToAddressFields && (
                <CustomerAddressForm
                    address={newAddress}
                    countries={countries}
                    addressFieldDisplayCollection={shipToAddressFields}
                    onSubmit={newShippingAddressFormSubmitHandler}
                    saveButtonTextOverride={translate("Save & Apply")}
                    onCancel={createNewAddressCancelHandler}
                    extendedStyles={styles.addCustomerAddressForm}
                />
            )}
        </>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(withHistory(withToaster(AddressBook))),
    definition: {
        group: "Address Book Overlay",
        allowedContexts: ["AddressBookOverlay"],
    },
};

export default widgetModule;
