import StyledWrapper, { getStyledWrapper } from "@insite/client-framework/Common/StyledWrapper";
import { CartLineContext } from "@insite/client-framework/Components/CartLineContext";
import { API_URL_CURRENT_FRAGMENT } from "@insite/client-framework/Services/ApiService";
import siteMessage from "@insite/client-framework/SiteMessage";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import {
    getCurrentCartState,
    hasProductsWithInvalidPrice,
} from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getCurrentPromotionsDataView } from "@insite/client-framework/Store/Data/Promotions/PromotionsSelectors";
import clearCurrentCart from "@insite/client-framework/Store/Pages/Cart/Handlers/ClearCurrentCart";
import removeCartLine from "@insite/client-framework/Store/Pages/Cart/Handlers/RemoveCartLine";
import updateCartLine from "@insite/client-framework/Store/Pages/Cart/Handlers/UpdateCartLine";
import translate from "@insite/client-framework/Translate";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import { CardContainerStyles } from "@insite/content-library/Components/CardContainer";
import { CardListStyles } from "@insite/content-library/Components/CardList";
import TwoButtonModal from "@insite/content-library/Components/TwoButtonModal";
import CartLineCardCondensed, {
    CartLineCardCondensedStyles,
} from "@insite/content-library/Widgets/Cart/CartLineCardCondensed";
import CartLineCardExpanded, {
    CartLineCardExpandedStyles,
} from "@insite/content-library/Widgets/Cart/CartLineCardExpanded";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import Checkbox, { CheckboxPresentationProps, CheckboxProps } from "@insite/mobius/Checkbox";
import CheckboxGroup, { CheckboxGroupComponentProps } from "@insite/mobius/CheckboxGroup";
import Clickable from "@insite/mobius/Clickable";
import Hidden from "@insite/mobius/Hidden";
import Icon, { IconPresentationProps } from "@insite/mobius/Icon";
import ShoppingCart from "@insite/mobius/Icons/ShoppingCart";
import Link, { LinkPresentationProps } from "@insite/mobius/Link";
import LoadingOverlay, { LoadingOverlayProps } from "@insite/mobius/LoadingOverlay";
import LoadingSpinner, { LoadingSpinnerProps } from "@insite/mobius/LoadingSpinner";
import OverflowMenu, { OverflowMenuPresentationProps } from "@insite/mobius/OverflowMenu";
import Typography, { TypographyProps } from "@insite/mobius/Typography";
import { FieldSetGroupPresentationProps } from "@insite/mobius/utilities/fieldSetProps";
import getColor from "@insite/mobius/utilities/getColor";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import VisuallyHidden from "@insite/mobius/VisuallyHidden";
import * as cssLinter from "css";
import React, { FC, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const enum fields {
    showLineNotes = "showLineNotes",
    showImage = "showImage",
    showProductTitle = "showProductTitle",
    showBrand = "showBrand",
    showRemoveAllActions = "showRemoveAllActions",
    showPerUnitPrice = "showPerUnitPrice",
    showPriceLabel = "showPriceLabel",
    showAddToList = "showAddToList",
    showItemCount = "showItemCount",
    showProductNumber = "showProductNumber",
    showBackToTop = "showBackToTop",
    showVmiBinDetails = "showVmiBinDetails",
    customCSS = "customCSS",
}

const basicTab = {
    displayName: "Basic",
    sortOrder: 0,
};

const advancedTab = {
    displayName: "Advanced",
    sortOrder: 1,
};

const defaultCustomCss = `.main-grid-container{
}

.title-grid-item{
}

.title{
}

.description-grid-item{
}

.description-text{
}

.email-grid-item{
}

.email-text-field{
}

.email-button{
}

.disclaimer-grid-item{
}

.disclaimer-text{
}`;

interface OwnProps extends WidgetProps {
    fields: {
        [fields.showLineNotes]: boolean;
        [fields.showImage]: boolean;
        [fields.showProductTitle]: boolean;
        [fields.showBrand]: boolean;
        [fields.showRemoveAllActions]: boolean;
        [fields.showPerUnitPrice]: boolean;
        [fields.showPriceLabel]: boolean;
        [fields.showAddToList]: boolean;
        [fields.showItemCount]: boolean;
        [fields.showProductNumber]: boolean;
        [fields.showBackToTop]: boolean;
        [fields.showVmiBinDetails]: boolean;
        [fields.customCSS]: string;
    };
}

const mapStateToProps = (state: ApplicationState) => ({
    cart: getCurrentCartState(state).value,
    promotionsDataView: getCurrentPromotionsDataView(state),
    settingsCollection: getSettingsCollection(state),
    isClearingCart: state.pages.cart.isClearingCart,
    isUpdatingCartLine: state.pages.cart.isUpdatingCartLine,
    isLoading: state.data.carts.isLoading,
    isRemovingCartLine: Object.getOwnPropertyNames(state.pages.cart.isRemovingCartLine).length > 0,
    showPricing: state.context.showPricing,
    showInventory: state.context.showInventory,
});

const mapDispatchToProps = {
    clearCurrentCart,
    updateCartLine,
    removeCartLine,
};

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

export interface CartLinesStyles {
    wrapper?: InjectableCss;
    loadingOverlay?: LoadingOverlayProps;
    centeringWrapper?: InjectableCss;
    spinner?: LoadingSpinnerProps;
    noCartLinesText?: TypographyProps;
    noCartLinesIcon?: IconPresentationProps;
    headerWrapper?: InjectableCss;
    header?: CartLinesHeaderStyles;
    cardList?: CardListStyles;
    cardContainer?: CardContainerStyles;
    cardExpanded?: CartLineCardExpandedStyles;
    cardCondensed?: CartLineCardCondensedStyles;
    footerWrapper?: InjectableCss;
    backToTopButton?: ButtonPresentationProps;
}

interface CartLinesHeaderStyles {
    itemCountText?: TypographyProps;
    condensedViewCheckboxGroup?: FieldSetGroupPresentationProps<CheckboxGroupComponentProps>;
    condensedViewCheckbox?: CheckboxPresentationProps;
    overflowMenu?: OverflowMenuPresentationProps;
    removeAllLink?: LinkPresentationProps;
    mainSection?: InjectableCss;
    warningIcon?: IconPresentationProps;
    warningSection?: InjectableCss;
    warningText?: InjectableCss;
}

export const cartLinesStyles: CartLinesStyles = {
    centeringWrapper: {
        css: css`
            display: flex;
            flex-direction: column;
            height: 300px;
            justify-content: center;
            align-items: center;
        `,
    },
    noCartLinesText: {
        variant: "h3",
    },
    noCartLinesIcon: {
        src: ShoppingCart,
        size: 45,
        color: "text.link",
        css: css`
            margin-bottom: 20px;
        `,
    },
    headerWrapper: {
        css: css`
            border-bottom: 1px solid ${getColor("common.border")};
            padding-bottom: 10px;
        `,
    },
    header: {
        condensedViewCheckboxGroup: {
            css: css`
                margin-left: auto;
            `,
        },
        condensedViewCheckbox: {
            typographyProps: {
                css: css`
                    margin-left: 10px;
                `,
            },
        },
        overflowMenu: {
            cssOverrides: {
                wrapper: css`
                    margin-left: 20px;
                `,
            },
        },
        removeAllLink: {
            css: css`
                margin-left: 24px;
            `,
        },
        mainSection: {
            css: css`
                display: flex;
                align-items: center;
                padding-bottom: 5px;
            `,
        },
        warningIcon: {
            src: "AlertCircle",
            color: "danger.main",
            css: css`
                margin-right: 10px;
            `,
        },
        warningSection: {
            css: css`
                display: flex;
                align-items: center;
                border: 2px solid ${getColor("danger.main")};
                padding: 15px 10px;
            `,
        },
    },
    footerWrapper: {
        css: css`
            display: flex;
            justify-content: center;
        `,
    },
    backToTopButton: {
        variant: "secondary",
        css: css`
            margin: 16px 0;
        `,
    },
};

const StyledSection = getStyledWrapper("section");

const styles = cartLinesStyles;

const CartLines: FC<Props> = ({
    cart,
    promotionsDataView,
    settingsCollection,
    clearCurrentCart,
    fields,
    isClearingCart,
    isUpdatingCartLine,
    isLoading,
    updateCartLine,
    removeCartLine,
    isRemovingCartLine,
    showPricing,
    showInventory,
}) => {
    const [isCondensed, setIsCondensed] = useState(false);
    const [isRemoveAllModalOpen, setIsRemoveAllModalOpen] = useState(false);

    if (!cart || (cart.lineCount && !cart.cartLines) || isClearingCart) {
        return (
            <StyledSection {...styles.centeringWrapper}>
                <LoadingSpinner {...styles.spinner} />
            </StyledSection>
        );
    }

    const cartLines = cart.cartLines || [];

    if (cartLines.length === 0) {
        return (
            <StyledSection {...styles.centeringWrapper}>
                <Icon {...styles.noCartLinesIcon} />
                <Typography {...styles.noCartLinesText} data-test-selector="cart_noCartLinesMessage">
                    {siteMessage("Cart_NoOrderLines")}
                </Typography>
            </StyledSection>
        );
    }

    const isCondensedChangeHandler: CheckboxProps["onChange"] = (_, value) => {
        setIsCondensed(value);
    };

    const removeAllClickHandler = () => {
        if (cart.status === "AwaitingApproval") {
            setIsRemoveAllModalOpen(true);
        } else {
            clearCurrentCart();
        }
    };

    const submitRemoveAllClickHandler = () => {
        setIsRemoveAllModalOpen(false);
        clearCurrentCart();
    };

    const { productSettings } = settingsCollection;
    const { value: promotions } = promotionsDataView;
    const productsCannotBePurchased = cartLines.some(o => o.isRestricted || !o.isActive || o.cantBuy);
    const isLoadingCart =
        isLoading[cart.id] || (cart.status === "AlternateCart" && isLoading[API_URL_CURRENT_FRAGMENT]);

    const cartLinesDisplay = cartLines.map(cartLine => {
        if (!showPricing && cartLine.isPromotionItem) {
            return;
        }

        const matchingPromotions = promotions ? promotions.filter(promo => promo.orderLineId === cartLine.id) : [];
        const showRemoveAction = !cartLine.isPromotionItem && cart.canModifyOrder;
        return (
            <CartLineContext.Provider value={cartLine} key={cartLine.id}>
                {isCondensed ? (
                    <CartLineCardCondensed
                        cart={cart}
                        promotions={matchingPromotions}
                        productSettings={productSettings}
                        showInventoryAvailability={showInventory}
                        extendedStyles={styles.cardCondensed}
                        updateCartLine={updateCartLine}
                        removeCartLine={removeCartLine}
                        showRemoveAction={showRemoveAction}
                        showVmiBinDetails={fields.showVmiBinDetails}
                    />
                ) : (
                    <CartLineCardExpanded
                        cart={cart}
                        promotions={matchingPromotions}
                        productSettings={productSettings}
                        showInventoryAvailability={showInventory}
                        showLineNotes={fields.showLineNotes}
                        showImage={fields.showImage}
                        showProductTitle={fields.showProductTitle}
                        showBrand={fields.showBrand}
                        showPerUnitPrice={fields.showPerUnitPrice}
                        showPriceLabel={fields.showPriceLabel}
                        showAddToList={fields.showAddToList}
                        showProductNumber={fields.showProductNumber}
                        extendedStyles={styles.cardExpanded}
                        updateCartLine={updateCartLine}
                        removeCartLine={removeCartLine}
                        showRemoveAction={showRemoveAction}
                        showVmiBinDetails={fields.showVmiBinDetails}
                    />
                )}
            </CartLineContext.Provider>
        );
    });

    const customCssWrapper = {
        css: css`
            ${fields.customCSS}
        `,
    };

    return (
        <StyledWrapper {...customCssWrapper}>
            <StyledSection {...styles.wrapper}>
                <LoadingOverlay
                    {...styles.loadingOverlay}
                    loading={isLoadingCart || isUpdatingCartLine || !promotionsDataView.value || isRemovingCartLine}
                >
                    <CartLinesHeader
                        totalItemCount={cartLines.length}
                        isCondensed={isCondensed}
                        productsCannotBePurchased={productsCannotBePurchased}
                        cartNotPriced={cart.cartNotPriced}
                        hasInsufficientInventory={cart.hasInsufficientInventory}
                        hasInvalidPrice={hasProductsWithInvalidPrice(cart)}
                        failedToGetRealTimeInventory={cart.failedToGetRealTimeInventory}
                        onIsCondensedChange={isCondensedChangeHandler}
                        onRemoveAllClick={removeAllClickHandler}
                        showItemCount={fields.showItemCount}
                        showRemoveAllActions={fields.showRemoveAllActions}
                        fulfillmentMethod={cart.fulfillmentMethod}
                    />
                    {cartLinesDisplay}
                    {fields.showBackToTop !== false && <CartLinesFooter />}
                    <TwoButtonModal
                        headlineText={translate("Are you sure?")}
                        modalIsOpen={isRemoveAllModalOpen}
                        messageText={siteMessage("OrderApproval_RemoveAllConfirmationMessage")}
                        cancelButtonText={translate("Cancel")}
                        submitButtonText={translate("Clear cart and delete order")}
                        onCancel={() => setIsRemoveAllModalOpen(false)}
                        onSubmit={submitRemoveAllClickHandler}
                    ></TwoButtonModal>
                </LoadingOverlay>
            </StyledSection>
        </StyledWrapper>
    );
};

interface CartLinesHeaderProps {
    totalItemCount: number;
    isCondensed: boolean;
    productsCannotBePurchased?: boolean;
    cartNotPriced?: boolean;
    hasInsufficientInventory?: boolean;
    hasInvalidPrice?: boolean;
    failedToGetRealTimeInventory?: boolean;
    onIsCondensedChange: CheckboxProps["onChange"];
    onRemoveAllClick: () => void;
    showItemCount?: boolean;
    showRemoveAllActions?: boolean;
    fulfillmentMethod?: string;
}

const CartLinesHeader: FC<CartLinesHeaderProps> = ({
    totalItemCount,
    isCondensed,
    productsCannotBePurchased,
    cartNotPriced,
    hasInsufficientInventory,
    hasInvalidPrice,
    failedToGetRealTimeInventory,
    onIsCondensedChange,
    onRemoveAllClick,
    showItemCount = true,
    showRemoveAllActions = true,
    fulfillmentMethod,
}) => {
    const headerStyles = styles.header || {};

    return (
        <StyledSection {...styles.headerWrapper} id="cartHeader">
            <StyledSection {...headerStyles.mainSection}>
                {showItemCount && (
                    <Typography {...headerStyles.itemCountText}>{`${totalItemCount} ${translate("Items")}`}</Typography>
                )}
                <CheckboxGroup {...headerStyles.condensedViewCheckboxGroup}>
                    <Checkbox
                        checked={isCondensed}
                        onChange={onIsCondensedChange}
                        data-test-selector="cartlineHeader_condensedCheckbox"
                        {...headerStyles.condensedViewCheckbox}
                    >
                        {translate("Condensed View")}
                        <VisuallyHidden>{translate("for product list")}</VisuallyHidden>
                    </Checkbox>
                </CheckboxGroup>
                {showRemoveAllActions && (
                    <Hidden above="md">
                        <OverflowMenu position="end" {...headerStyles.overflowMenu}>
                            <Clickable onClick={onRemoveAllClick}>{translate("Remove All")}</Clickable>
                        </OverflowMenu>
                    </Hidden>
                )}
                {showRemoveAllActions && (
                    <Hidden below="lg">
                        <Link
                            onClick={onRemoveAllClick}
                            {...headerStyles.removeAllLink}
                            data-test-selector="cartlineHeader_removeAll"
                        >
                            {translate("Remove All")}
                        </Link>
                    </Hidden>
                )}
            </StyledSection>
            {productsCannotBePurchased && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography
                        {...headerStyles.warningText}
                        data-test-selector="cartlineHeader_warningProductsCannotBePurchased"
                    >
                        {siteMessage("Cart_ProductsCannotBePurchased")}
                    </Typography>
                </StyledSection>
            )}
            {cartNotPriced && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography
                        {...headerStyles.warningText}
                        data-test-selector="cartlineHeader_NoPriceAvailableAtCheckout"
                    >
                        {siteMessage("Cart_NoPriceAvailableAtCheckout")}
                    </Typography>
                </StyledSection>
            )}
            {hasInsufficientInventory && fulfillmentMethod === "Ship" && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography
                        {...headerStyles.warningText}
                        data-test-selector="cartlineHeader_warningInsufficientInventoryAtCheckout"
                    >
                        {siteMessage("Cart_InsufficientInventoryAtCheckout")}
                    </Typography>
                </StyledSection>
            )}
            {hasInsufficientInventory && fulfillmentMethod === "PickUp" && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography
                        {...headerStyles.warningText}
                        data-test-selector="cartlineHeader_warningInsufficientPickupInventory"
                    >
                        {siteMessage("Cart_InsufficientPickupInventory")}
                    </Typography>
                </StyledSection>
            )}
            {!cartNotPriced && hasInvalidPrice && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography {...headerStyles.warningText}>{siteMessage("Cart_InvalidPriceAtCheckout")}</Typography>
                </StyledSection>
            )}
            {failedToGetRealTimeInventory && (
                <StyledSection {...headerStyles.warningSection}>
                    <Icon {...headerStyles.warningIcon}></Icon>
                    <Typography {...headerStyles.warningText}>
                        {siteMessage("Cart_NoInventoryAvailableAtCheckout")}
                    </Typography>
                </StyledSection>
            )}
        </StyledSection>
    );
};

const CartLinesFooter: FC = () => {
    const backToTopClickHandler = () => {
        const header = document.getElementById("cartHeader");
        if (header) {
            window.scrollTo(0, header.offsetTop);
        }
    };

    return (
        <StyledSection {...styles.footerWrapper}>
            <Button onClick={backToTopClickHandler} {...styles.backToTopButton}>
                {translate("Back to Top")}
            </Button>
        </StyledSection>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(CartLines),
    definition: {
        group: "Cart",
        allowedContexts: ["CartPage"],
        fieldDefinitions: [
            {
                name: fields.showLineNotes,
                displayName: "Show Line Notes",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                fieldType: "General",
                isRequired: false,
                variant: "toggle",
                tooltip: "This setting does not apply to Punchout orders, which will never display Line Notes.",
                tab: basicTab,
                sortOrder: 0,
            },
            {
                name: fields.showImage,
                displayName: "Image",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => false,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 1,
            },
            {
                name: fields.showProductTitle,
                displayName: "Product title",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => false,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 2,
            },
            {
                name: fields.showBrand,
                displayName: "Brand",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 3,
            },
            {
                name: fields.showRemoveAllActions,
                displayName: "Remove all actions",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 4,
            },
            {
                name: fields.showPerUnitPrice,
                displayName: "Per unit price",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 5,
            },
            {
                name: fields.showPriceLabel,
                displayName: "Price label",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 6,
            },
            {
                name: fields.showAddToList,
                displayName: "Add to list",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 7,
            },
            {
                name: fields.showItemCount,
                displayName: "Item count",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 8,
            },
            {
                name: fields.showProductNumber,
                displayName: "Product number",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 9,
            },
            {
                name: fields.showBackToTop,
                displayName: "Back to top",
                editorTemplate: "CheckboxField",
                defaultValue: true,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 10,
            },
            {
                name: fields.showVmiBinDetails,
                displayName: "VMI Bin details",
                editorTemplate: "CheckboxField",
                defaultValue: false,
                isEnabled: () => true,
                fieldType: "General",
                tab: basicTab,
                sortOrder: 11,
            },
            {
                name: fields.customCSS,
                displayName: "Custom CSS",
                editorTemplate: "CodeField",
                fieldType: "General",
                tab: advancedTab,
                defaultValue: defaultCustomCss,
                isVisible: (item, shouldDisplayAdvancedFeatures) => !!shouldDisplayAdvancedFeatures,
                validate: value => {
                    if (value === undefined || value === null) {
                        return "";
                    }

                    const result = cssLinter.parse(value, { silent: true });
                    if (result?.stylesheet?.parsingErrors) {
                        // the error output at this time only has room for one line so we just show the first error
                        return result.stylesheet.parsingErrors.length <= 0
                            ? ""
                            : result.stylesheet.parsingErrors.map(error => `${error.reason} on line ${error.line}`)[0];
                    }

                    return "Unable to parse Css";
                },
                options: {
                    mode: "css",
                    lint: true,
                    autoRefresh: true,
                },
            },
        ],
    },
};

export default widgetModule;
