import mergeToNew from "@insite/client-framework/Common/mergeToNew";
import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getAddressFieldsDataView } from "@insite/client-framework/Store/Data/AddressFields/AddressFieldsSelector";
import { getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getCurrentCountries } from "@insite/client-framework/Store/Data/Countries/CountriesSelectors";
import { getShipTosDataView, getShipToState } from "@insite/client-framework/Store/Data/ShipTos/ShipTosSelectors";
import { getPageLinkByPageType } from "@insite/client-framework/Store/Links/LinksSelectors";
import updateShipTo from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/UpdateShipTo";
import translate from "@insite/client-framework/Translate";
import { BaseAddressModel, ShipToModel } from "@insite/client-framework/Types/ApiModels";
import CustomerAddressForm, { CustomerAddressFormStyles } from "@insite/content-library/Components/CustomerAddressForm";
import ShipToSelector, { ShipToSelectorStyles } from "@insite/content-library/Components/ShipToSelector";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import Modal, { ModalPresentationProps } from "@insite/mobius/Modal";
import { HasToasterContext, withToaster } from "@insite/mobius/Toast/ToasterContext";
import { HasHistory, withHistory } from "@insite/mobius/utilities/HistoryContext";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import React, { useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

interface OwnProps {
    isOpen: boolean;
    onModalClose: () => void;
    extendedStyles?: ShipToSelectorModalStyles;
}

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

const mapStateToProps = (state: ApplicationState) => {
    const cart = getCurrentCartState(state).value;
    return {
        cart,
        currentShipTo: getShipToState(state, cart ? cart.shipToId : undefined).value,
        shipTosDataView: cart
            ? getShipTosDataView(state, { billToId: cart.billToId, expand: ["validation"], exclude: ["showAll"] })
            : undefined,
        cartPageUrl: getPageLinkByPageType(state, "CartPage")?.url,
        countries: getCurrentCountries(state),
        shipToAddressFields: getAddressFieldsDataView(state).value?.shipToAddressFields,
    };
};

const mapDispatchToProps = {
    updateShipTo,
};

export interface ShipToSelectorModalStyles {
    modal?: ModalPresentationProps;
    shipToSelector?: ShipToSelectorStyles;
    buttonsWrapper?: InjectableCss;
    cancelButton?: ButtonPresentationProps;
    addCustomerAddressForm?: CustomerAddressFormStyles;
    editCustomerAddressForm?: CustomerAddressFormStyles;
}

export const shipToSelectorModalStyles: ShipToSelectorModalStyles = {
    modal: { sizeVariant: "medium" },
    buttonsWrapper: {
        css: css`
            display: flex;
            justify-content: flex-end;
            margin-top: 1rem;
        `,
    },
    cancelButton: { variant: "secondary" },
};

const ShipToSelectorModal = ({
    cart,
    currentShipTo,
    shipTosDataView,
    cartPageUrl,
    countries,
    shipToAddressFields,
    isOpen,
    extendedStyles,
    history,
    toaster,
    updateShipTo,
    onModalClose,
}: Props) => {
    const [styles] = useState(() => mergeToNew(shipToSelectorModalStyles, extendedStyles));

    const [shiToBeingEdited, setShipToBeingEdited] = useState<ShipToModel | undefined>(undefined);
    const [isShipToCreating, setIsShipToCreating] = useState(false);

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

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

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

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

    const newShipToFormSubmitHandler = (_: React.FormEvent<HTMLFormElement>, address: ShipToModel) => {
        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);
        onModalClose();
    };

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

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

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

    return (
        <Modal
            {...styles.modal}
            headline={
                isShipToCreating
                    ? translate("Create New Address")
                    : shiToBeingEdited
                    ? translate("Edit Address")
                    : translate("Address Book")
            }
            isOpen={isOpen}
            handleClose={onModalClose}
            data-test-selector="onePageCheckoutShipping_addressModal"
        >
            {!shiToBeingEdited && !isShipToCreating && (
                <>
                    <ShipToSelector
                        currentShipTo={currentShipTo}
                        currentBillToId={cart?.billToId}
                        newAddress={newAddress}
                        allowSelectBillTo={true}
                        onSelect={selectShipToHandler}
                        onEdit={editShipToHandler}
                        onCreateNewAddressClick={newAddress && createNewAddressHandler}
                        extendedStyles={styles.shipToSelector}
                    />
                    <StyledWrapper {...styles.buttonsWrapper}>
                        <Button {...styles.cancelButton} onClick={onModalClose}>
                            {translate("Cancel")}
                        </Button>
                    </StyledWrapper>
                </>
            )}
            {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={newShipToFormSubmitHandler}
                    onCancel={createNewAddressCancelHandler}
                    extendedStyles={styles.addCustomerAddressForm}
                />
            )}
        </Modal>
    );
};

export default connect(mapStateToProps, mapDispatchToProps)(withHistory(withToaster(ShipToSelectorModal)));
