import { parserOptions } from "@insite/client-framework/Common/BasicSelectors";
import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import { makeHandlerChainAwaitable } from "@insite/client-framework/HandlerCreator";
import { FulfillmentMethod } from "@insite/client-framework/Services/SessionService";
import siteMessage from "@insite/client-framework/SiteMessage";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import setStorePickupOverlayIsOpen from "@insite/client-framework/Store/Components/StorePickupOverlay/Handlers/SetStorePickupOverlayIsOpen";
import { getSession, getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import setFulfillmentMethod from "@insite/client-framework/Store/Context/Handlers/SetFulfillmentMethod";
import updatePickUpWarehouse from "@insite/client-framework/Store/Context/Handlers/UpdatePickUpWarehouse";
import { getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import setFulfillmentMethodForCart from "@insite/client-framework/Store/Data/Carts/Handlers/SetFulfillmentMethod";
import updatePickUpWarehouseForCart from "@insite/client-framework/Store/Data/Carts/Handlers/UpdatePickUpWarehouse";
import translate from "@insite/client-framework/Translate";
import { WarehouseModel } from "@insite/client-framework/Types/ApiModels";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import AddressInfoDisplay, { AddressInfoDisplayStyles } from "@insite/content-library/Components/AddressInfoDisplay";
import FindLocationModal, { FindLocationModalStyles } from "@insite/content-library/Components/FindLocationModal";
import { BaseTheme } from "@insite/mobius/globals/baseTheme";
import Link, { LinkPresentationProps } from "@insite/mobius/Link";
import Radio, { RadioComponentProps } from "@insite/mobius/Radio";
import RadioGroup, { RadioGroupComponentProps } from "@insite/mobius/RadioGroup";
import ToasterContext from "@insite/mobius/Toast/ToasterContext";
import Typography, { TypographyPresentationProps, TypographyProps } from "@insite/mobius/Typography";
import FieldSetPresentationProps, { FieldSetGroupPresentationProps } from "@insite/mobius/utilities/fieldSetProps";
import getColor from "@insite/mobius/utilities/getColor";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import parse from "html-react-parser";
import React, { useContext, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css, ThemeProps, withTheme } from "styled-components";

const enum fields {
    displayStyle = "displayStyle",
    shipToHomeMessage = "shipToHomeMessage",
    storePickUpMessage = "storePickUpMessage",
}

interface OwnProps extends WidgetProps {
    fields: {
        [fields.displayStyle]: string;
        [fields.shipToHomeMessage]: string;
        [fields.storePickUpMessage]: string;
    };
}

const mapStateToProps = (state: ApplicationState) => {
    const cart = getCurrentCartState(state).value;
    const session = getSession(state);
    return {
        fulfillmentMethod: cart?.fulfillmentMethod || session.fulfillmentMethod,
        enableWarehousePickup: getSettingsCollection(state).accountSettings.enableWarehousePickup,
        pickUpWarehouse: cart?.defaultWarehouse || session.pickUpWarehouse,
        updateCartInsteadOfContext: cart?.isAwaitingApproval,
        cart,
    };
};

const mapDispatchToProps = {
    setFulfillmentMethod,
    updatePickUpWarehouse: makeHandlerChainAwaitable(updatePickUpWarehouse),
    setStorePickupOverlayIsOpen,
    setFulfillmentMethodForCart,
    updatePickUpWarehouseForCart: makeHandlerChainAwaitable(updatePickUpWarehouseForCart),
};

type Props = OwnProps &
    ReturnType<typeof mapStateToProps> &
    ResolveThunks<typeof mapDispatchToProps> &
    ThemeProps<BaseTheme>;

export interface CartFulfillmentMethodSelectorStyles {
    fulfillmentMethodradioGroup?: FieldSetGroupPresentationProps<RadioGroupComponentProps>;
    fulfillmentMethodRadio?: FieldSetPresentationProps<RadioComponentProps>;
    pickUpLocation?: PickUpLocationStyles;
    clickableBoxesText?: TypographyPresentationProps;
    boxesWrapper?: InjectableCss;
    boxWrapper?: InjectableCss;
    selectedBoxWrapper?: InjectableCss;
    clickableBoxLabel?: TypographyPresentationProps;
    pickUpWarehouseLink?: LinkPresentationProps;
    shipToHomeMessage?: TypographyPresentationProps;
    storePickUpMessage?: TypographyPresentationProps;
    findLocationModal?: FindLocationModalStyles;
}

interface PickUpLocationStyles {
    wrapper?: InjectableCss;
    headerText?: TypographyProps;
    changeLink?: LinkPresentationProps;
    warehouseAddress?: WarehouseAddressInfoDisplayStyles;
}

interface WarehouseAddressInfoDisplayStyles {
    wrapper?: InjectableCss;
    nameText?: TypographyProps;
    address?: AddressInfoDisplayStyles;
}

export const cartFulfillmentMethodStyles: CartFulfillmentMethodSelectorStyles = {
    pickUpLocation: {
        wrapper: {
            css: css`
                margin-top: 20px;
            `,
        },
        headerText: {
            weight: 600,
        },
        changeLink: {
            css: css`
                margin-left: 15px;
            `,
        },
        warehouseAddress: {
            wrapper: {
                css: css`
                    margin-top: 8px;
                `,
            },
            nameText: {
                as: "p",
            },
        },
    },
    boxesWrapper: {
        css: css`
            display: flex;
            gap: 8px;
        `,
    },
    boxWrapper: {
        css: css`
            border: 1px solid ${getColor("common.border")};
            padding: 15px;
            margin-top: 15px;
            display: flex;
            flex-direction: column;
            width: 50%;
            align-items: flex-start;
            cursor: pointer;
        `,
    },
    selectedBoxWrapper: {
        css: css`
            border: 2px solid ${getColor("secondary.main")};
            padding: 15px;
            margin-top: 15px;
            display: flex;
            flex-direction: column;
            width: 50%;
            align-items: flex-start;
            cursor: pointer;
        `,
    },
    clickableBoxLabel: {
        css: css`
            margin-bottom: 8px;
        `,
    },
};

const styles = cartFulfillmentMethodStyles;

const CartFulfillmentMethodSelector = ({
    fulfillmentMethod,
    enableWarehousePickup,
    pickUpWarehouse,
    fields,
    setFulfillmentMethod,
    updatePickUpWarehouse,
    setStorePickupOverlayIsOpen,
    theme,
    updateCartInsteadOfContext,
    setFulfillmentMethodForCart,
    updatePickUpWarehouseForCart,
    cart,
}: Props) => {
    const [isFindLocationOpen, setIsFindLocationOpen] = useState(false);
    const toasterContext = useContext(ToasterContext);
    if (!fulfillmentMethod || !enableWarehousePickup) {
        return null;
    }

    const { shipToHomeMessage, storePickUpMessage } = fields;
    const displayStyle = fields.displayStyle || "radioButton";
    const fulfillmentMethodChangeHandler = (fulfillmentMethod: string) => {
        if (updateCartInsteadOfContext && cart) {
            setFulfillmentMethodForCart({
                cart,
                fulfillmentMethod: fulfillmentMethod as "Ship" | "PickUp",
            });
        } else {
            setFulfillmentMethod({ fulfillmentMethod: fulfillmentMethod as "Ship" | "PickUp" });
        }
    };

    const handlePickUpAddressChange = async (pickUpWarehouse: WarehouseModel) => {
        if (updateCartInsteadOfContext && cart) {
            await updatePickUpWarehouseForCart({ cart, pickUpWarehouse });
        } else {
            await updatePickUpWarehouse({ pickUpWarehouse });
        }

        toasterContext.addToast({
            body: translate("Pick Up Address Updated"),
            messageType: "success",
        });
    };

    const handleOpenFindLocation = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
        event.stopPropagation();

        if (theme.storePickup?.useOverlay) {
            setStorePickupOverlayIsOpen({ isOpen: true });
            return;
        }

        setIsFindLocationOpen(true);
    };
    const handleFindLocationModalClose = () => setIsFindLocationOpen(false);
    const handleWarehouseSelected = (warehouse: WarehouseModel) => {
        handlePickUpAddressChange(warehouse);
        setIsFindLocationOpen(false);
    };

    return (
        <>
            {displayStyle === "radioButton" && (
                <>
                    <RadioGroup
                        label={translate("Fulfillment Method")}
                        value={fulfillmentMethod}
                        onChangeHandler={event => fulfillmentMethodChangeHandler(event.currentTarget.value)}
                        {...styles.fulfillmentMethodradioGroup}
                        data-test-selector="cartFulfillmentMethod"
                    >
                        <Radio
                            value={FulfillmentMethod.Ship}
                            {...styles.fulfillmentMethodRadio}
                            data-test-selector="fulfillmentMethod_ship"
                        >
                            {translate("Ship")}
                        </Radio>
                        <Radio
                            value={FulfillmentMethod.PickUp}
                            {...styles.fulfillmentMethodRadio}
                            data-test-selector="fulfillmentMethod_pickUp"
                        >
                            {translate("Pick Up")}
                        </Radio>
                    </RadioGroup>
                    {fulfillmentMethod === FulfillmentMethod.PickUp && pickUpWarehouse && (
                        <PickUpLocation warehouse={pickUpWarehouse} openFindLocation={handleOpenFindLocation} />
                    )}
                </>
            )}
            {displayStyle === "clickableBoxes" && (
                <>
                    <Typography {...styles.clickableBoxesText}>
                        {siteMessage("Cart_FulfillmentMethodMessage")}
                    </Typography>
                    <StyledWrapper {...styles.boxesWrapper}>
                        <StyledWrapper
                            {...(fulfillmentMethod === FulfillmentMethod.Ship
                                ? styles.selectedBoxWrapper
                                : styles.boxWrapper)}
                            onClick={() => fulfillmentMethodChangeHandler(FulfillmentMethod.Ship)}
                        >
                            <Typography {...styles.clickableBoxLabel}>{translate("Ship to home")}</Typography>
                            <Typography {...styles.shipToHomeMessage}>
                                {parse(shipToHomeMessage || "", parserOptions)}
                            </Typography>
                        </StyledWrapper>
                        <StyledWrapper
                            {...(fulfillmentMethod === FulfillmentMethod.PickUp
                                ? styles.selectedBoxWrapper
                                : styles.boxWrapper)}
                            onClick={() => fulfillmentMethodChangeHandler(FulfillmentMethod.PickUp)}
                        >
                            <Typography {...styles.clickableBoxLabel}>
                                {pickUpWarehouse ? translate("Store pickup at") : translate("Store pickup")}
                                {pickUpWarehouse && (
                                    <Link onClick={handleOpenFindLocation} {...styles.pickUpWarehouseLink}>
                                        &nbsp;{pickUpWarehouse.description || pickUpWarehouse.name}
                                    </Link>
                                )}
                            </Typography>
                            <Typography {...styles.storePickUpMessage}>
                                {parse(storePickUpMessage || "", parserOptions)}
                            </Typography>
                        </StyledWrapper>
                    </StyledWrapper>
                </>
            )}
            <FindLocationModal
                modalIsOpen={isFindLocationOpen}
                onWarehouseSelected={handleWarehouseSelected}
                onModalClose={handleFindLocationModalClose}
                forCart
                extendedStyles={styles.findLocationModal}
            />
        </>
    );
};

interface PickUpLocationProps {
    warehouse: WarehouseModel;
    openFindLocation: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void;
}

const PickUpLocation = ({ warehouse, openFindLocation }: PickUpLocationProps) => {
    const componentStyles = styles.pickUpLocation || {};

    return (
        <>
            <StyledWrapper {...componentStyles.wrapper} data-test-selector="cart_pickUpLocation">
                <Typography {...componentStyles.headerText}>{translate("Pick Up Location")}</Typography>
                <Link
                    onClick={openFindLocation}
                    {...componentStyles.changeLink}
                    data-test-selector="cart_pickUpLocation_findLocation"
                >
                    {translate("Change")}
                </Link>
                <WarehouseAddressInfoDisplay warehouse={warehouse} />
            </StyledWrapper>
        </>
    );
};

interface WarehouseAddressInfoDisplayProps {
    warehouse: WarehouseModel;
}

const WarehouseAddressInfoDisplay = ({ warehouse }: WarehouseAddressInfoDisplayProps) => {
    const componentStyles =
        styles.pickUpLocation && styles.pickUpLocation.warehouseAddress ? styles.pickUpLocation.warehouseAddress : {};

    return (
        <StyledWrapper {...componentStyles.wrapper}>
            <Typography {...componentStyles.nameText} data-test-selector="cart_warehouseName">
                {warehouse.description || warehouse.name}
            </Typography>
            <AddressInfoDisplay
                address1={warehouse.address1}
                address2={warehouse.address2}
                city={warehouse.city}
                state={warehouse.state}
                postalCode={warehouse.postalCode}
                phone={warehouse.phone}
                extendedStyles={componentStyles.address}
            />
        </StyledWrapper>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(withTheme(CartFulfillmentMethodSelector)),
    definition: {
        group: "Cart",
        displayName: "Fulfillment Method Selector",
        icon: "truck",
        allowedContexts: ["CartPage"],
        fieldDefinitions: [
            {
                name: fields.displayStyle,
                displayName: "Display Style",
                editorTemplate: "RadioButtonsField",
                options: [
                    {
                        displayName: "Radio Button",
                        value: "radioButton",
                    },
                    {
                        displayName: "Clickable Boxes",
                        value: "clickableBoxes",
                    },
                ],
                defaultValue: "radioButton",
                fieldType: "General",
            },
            {
                name: fields.shipToHomeMessage,
                displayName: "Ship to home message",
                defaultValue: "",
                editorTemplate: "RichTextField",
                fieldType: "Contextual",
                extendedConfig: { height: 100 },
                isVisible: item => item?.fields[fields.displayStyle] === "clickableBoxes",
            },
            {
                name: fields.storePickUpMessage,
                displayName: "Store PickUp message",
                defaultValue: "",
                editorTemplate: "RichTextField",
                fieldType: "Contextual",
                extendedConfig: { height: 100 },
                isVisible: item => item?.fields[fields.displayStyle] === "clickableBoxes",
            },
        ],
    },
};

export default widgetModule;
