import { parserOptions } from "@insite/client-framework/Common/BasicSelectors";
import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import { extractStylesToArray, isSafe } from "@insite/client-framework/Common/Utilities/isSafeStyles";
import parseQueryString from "@insite/client-framework/Common/Utilities/parseQueryString";
import siteMessage from "@insite/client-framework/SiteMessage";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import loadOrderByOrderNumber from "@insite/client-framework/Store/Data/Orders/Handlers/LoadOrderByOrderNumber";
import { getOrderState } from "@insite/client-framework/Store/Data/Orders/OrdersSelectors";
import { getLocation } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import cancelOrder from "@insite/client-framework/Store/Pages/OrderDetails/Handlers/CancelOrder";
import { canCancelOrder } from "@insite/client-framework/Store/Pages/OrderDetails/OrderDetailsSelectors";
import translate from "@insite/client-framework/Translate";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import { useMergeStyles } from "@insite/content-library/additionalStyles";
import TwoButtonModal, { TwoButtonModalStyles } from "@insite/content-library/Components/TwoButtonModal";
import { ContentWrapper } from "@insite/content-library/Widgets/Basic/RichContent";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import Typography, { TypographyProps } from "@insite/mobius/Typography";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import * as cssLinter from "css";
import parse from "html-react-parser";
import React, { useEffect, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const enum fields {
    layout = "layout",
    title = "title",
    description = "description",
    disclaimer = "disclaimer",
    buttonLabel = "buttonLabel",
    customCSS = "customCSS",
}

interface OwnProps extends WidgetProps {
    fields: {
        [fields.layout]: string;
        [fields.title]: string;
        [fields.description]: string;
        [fields.disclaimer]: string;
        [fields.buttonLabel]: string;
        [fields.customCSS]: string;
    };
}

const mapStateToProps = (state: ApplicationState) => {
    const location = getLocation(state);
    const parsedQuery = parseQueryString<{ cartId?: string }>(location.search);
    const cartState = getCartState(
        state,
        parsedQuery.cartId || state.pages.orderConfirmation.cartId || state.pages.onePageCheckoutConfirmation.cartId,
    );
    const orderNumber = state.pages.orderDetails?.orderNumber || cartState.value?.orderNumber;
    const orderState = getOrderState(state, orderNumber);
    const order = orderState.value;

    return {
        orderNumber,
        orderState,
        order,
        canCancel: canCancelOrder(state, order),
    };
};

const mapDispatchToProps = {
    loadOrderByOrderNumber,
    cancelOrder,
};

export interface OrderCancelStyles {
    titleText?: TypographyProps;
    descriptionText?: TypographyProps;
    disclaimerText?: TypographyProps;
    cancelButton?: ButtonPresentationProps;
    layoutWrapper?: InjectableCss;
    twoButtonModalStyles?: TwoButtonModalStyles;
}

export const orderCancelStyles: OrderCancelStyles = {
    titleText: {
        variant: "h2",
        css: css`
            @media print {
                font-size: 12px;
            }
            padding: 5px 0;
        `,
    },
    descriptionText: {
        css: css`
            padding: 5px 0;
        `,
    },
    disclaimerText: {
        css: css`
            padding: 5px 0;
        `,
    },
    cancelButton: {
        buttonType: "outline",
        variant: "secondary",
        css: css`
            margin: 10px 0;
        `,
    },
    layoutWrapper: {
        css: css`
            padding: 0;
            margin: 5px 0;
        `,
    },
    twoButtonModalStyles: {
        submitButton: {
            color: "primary",
        },
    },
};

const defaultCustomCss = `.order-cancel-wrapper {
}
.order-cancel-title {
}
.order-cancel-description {
}
.order-cancel-button {
}
.order-cancel-disclaimer {
}
`;

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

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

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

const OrderCancel = ({
    orderNumber,
    orderState,
    order,
    canCancel,
    fields,
    loadOrderByOrderNumber,
    cancelOrder,
}: Props) => {
    const styles = useMergeStyles("richContent", orderCancelStyles);
    const [cancelOrderModalIsOpen, setCancelOrderModalIsOpen] = useState(false);

    useEffect(() => {
        if (!orderState.isLoading && !orderState.value && orderNumber) {
            loadOrderByOrderNumber({ orderNumber });
        }
    }, [orderState]);

    if (!order || !order.canAddToCart || !canCancel) {
        return null;
    }

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

    const handleCancelOrderButtonClick = () => {
        setCancelOrderModalIsOpen(true);
    };

    const handleModalNoButtonClick = () => {
        setCancelOrderModalIsOpen(false);
    };

    const handleModalYesButtonClick = () => {
        setCancelOrderModalIsOpen(false);
        cancelOrder({ orderNumber: order.webOrderNumber ?? order.erpOrderNumber });
    };

    const alignmentStyles = {
        css: css`
            text-align: ${fields.layout || "center"};
            ${styles.layoutWrapper?.css}
        `,
    };

    return (
        <StyledWrapper {...customCssWrapper} data-test-selector="orderCancelWidget">
            <StyledWrapper {...alignmentStyles} className="order-cancel-wrapper">
                <Typography {...styles.titleText} className="order-cancel-title">
                    {fields.title}
                </Typography>
                <ContentWrapper {...styles.descriptionText} className="order-cancel-description">
                    {parse(fields.description, parserOptions)}
                </ContentWrapper>
                <Button
                    {...styles.cancelButton}
                    className="order-cancel-button"
                    onClick={handleCancelOrderButtonClick}
                    data-test-selector="orderCancelWidget_CancelButton"
                >
                    {fields.buttonLabel}
                </Button>
                <ContentWrapper {...styles.disclaimerText} className="order-cancel-disclaimer">
                    {parse(fields.disclaimer, parserOptions)}
                </ContentWrapper>
                <TwoButtonModal
                    modalIsOpen={cancelOrderModalIsOpen}
                    headlineText={translate("Cancel Order")}
                    messageText={siteMessage("Order_ConfirmCancelOrder")}
                    cancelButtonText={translate("No")}
                    submitButtonText={translate("Yes, Cancel Order")}
                    extendedStyles={styles.twoButtonModalStyles}
                    onCancel={handleModalNoButtonClick}
                    onSubmit={handleModalYesButtonClick}
                    submitTestSelector="submitButton"
                    cancelTestSelector="cancelButton"
                ></TwoButtonModal>
            </StyledWrapper>
        </StyledWrapper>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(OrderCancel),
    definition: {
        allowedContexts: [
            "OrderDetailsPage",
            "VmiOrderDetailsPage",
            "OrderConfirmationPage",
            "OnePageCheckoutConfirmationPage",
        ],
        group: "Order Details",
        fieldDefinitions: [
            {
                name: fields.layout,
                displayName: "Layout",
                editorTemplate: "RadioButtonsField",
                defaultValue: "center",
                horizontal: true,
                fieldType: "General",
                sortOrder: 0,
                tab: basicTab,
                options: [
                    {
                        displayName: "Left",
                        value: "left",
                    },
                    {
                        displayName: "Center",
                        value: "center",
                    },
                    {
                        displayName: "Right",
                        value: "right",
                    },
                ],
            },
            {
                name: fields.title,
                displayName: "Title",
                editorTemplate: "TextField",
                defaultValue: "Made a mistake?",
                fieldType: "Translatable",
                sortOrder: 1,
                tab: basicTab,
            },
            {
                name: fields.description,
                displayName: "Description",
                editorTemplate: "RichTextField",
                defaultValue:
                    "You have 24 hours from order placement time to cancel your order. Simply click Cancel Order.",
                fieldType: "Translatable",
                sortOrder: 2,
                extendedConfig: { height: 120 },
                validate: (html: string) => {
                    const arrayOfStyles = extractStylesToArray(html);
                    return arrayOfStyles?.every(style => isSafe(style))
                        ? null
                        : "The HTML contains invalid styles that prevent it from being saved";
                },
                tab: basicTab,
            },
            {
                name: fields.disclaimer,
                displayName: "Disclaimer",
                editorTemplate: "RichTextField",
                defaultValue: "For information about returns, please read our Return Policy",
                fieldType: "Translatable",
                sortOrder: 3,
                extendedConfig: { height: 100 },
                validate: (html: string) => {
                    const arrayOfStyles = extractStylesToArray(html);
                    return arrayOfStyles?.every(style => isSafe(style))
                        ? null
                        : "The HTML contains invalid styles that prevent it from being saved";
                },
                tab: basicTab,
            },
            {
                name: fields.buttonLabel,
                displayName: "Button Label",
                editorTemplate: "TextField",
                defaultValue: "Cancel Order",
                fieldType: "Translatable",
                sortOrder: 4,
                tab: basicTab,
            },
            {
                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;
