import { getCookie } from "@insite/client-framework/Common/Cookies";
import { getStyledWrapper } from "@insite/client-framework/Common/StyledWrapper";
import parseQueryString from "@insite/client-framework/Common/Utilities/parseQueryString";
import { makeHandlerChainAwaitable } from "@insite/client-framework/HandlerCreator";
import siteMessage from "@insite/client-framework/SiteMessage";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import validateReCaptcha from "@insite/client-framework/Store/Components/ReCaptcha/Handlers/ValidateReCaptcha";
import { getSession, getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import { getLocation } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import translate from "@insite/client-framework/Translate";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import ReCaptcha, { ReCaptchaStyles } from "@insite/content-library/Components/ReCaptcha";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import GridContainer, { GridContainerProps } from "@insite/mobius/GridContainer";
import GridItem, { GridItemProps } from "@insite/mobius/GridItem";
import TextField, { TextFieldPresentationProps } from "@insite/mobius/TextField";
import { breakpointMediaQueries } from "@insite/mobius/utilities";
import { HasHistory, withHistory } from "@insite/mobius/utilities/HistoryContext";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import React, { ReactNode, RefObject, useState } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const session = getSession(state);
    const location = getLocation(state);
    const parsedQuery = parseQueryString<{
        ordernumber?: string;
        stemail?: string;
        stpostalcode?: string;
        orderNumber?: string;
        stEmail?: string;
        stPostalCode?: string;
    }>(location.search);

    return {
        location,
        order: state.pages.orderStatus.order, // do not delete this, needed to trigger rendering and hide passed reCaptcha
        orderNumberFromQuery: parsedQuery.orderNumber ?? parsedQuery.ordernumber,
        emailOrPostalCodeFromQuery:
            parsedQuery.stEmail ?? parsedQuery.stemail ?? parsedQuery.stPostalCode ?? parsedQuery.stpostalcode ?? "",
        isAuthenticated: session && (session.isAuthenticated || session.rememberMe) && !session.isGuest,
        isReCaptchaEnabled: getSettingsCollection(state).websiteSettings.reCaptchaEnabledForOrderStatus,
    };
};

const mapDispatchToProps = {
    validateReCaptcha: makeHandlerChainAwaitable<
        { location: string; recaptchaRef: RefObject<ReCAPTCHA | null> },
        boolean
    >(validateReCaptcha),
};

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

export interface OrderStatusFormStyles {
    form?: InjectableCss;
    gridContainer?: GridContainerProps;
    orderNumberGridItem?: GridItemProps;
    orderNumberTextField?: TextFieldPresentationProps;
    emailOrPostalCodeGridItem?: GridItemProps;
    emailOrPostalCodeTextField?: TextFieldPresentationProps;
    submitButtonGridItem?: GridItemProps;
    submitButton?: ButtonPresentationProps;
    reCaptchaGridItem?: GridItemProps;
    reCaptcha?: ReCaptchaStyles;
}

export const orderStatusFormStyles: OrderStatusFormStyles = {
    orderNumberGridItem: { width: [12, 12, 12, 6, 3] },
    emailOrPostalCodeGridItem: { width: [12, 12, 12, 6, 3] },
    submitButtonGridItem: { width: [12, 12, 12, 12, 2] },
    submitButton: {
        css: css`
            margin-top: 32px;
            ${({ theme }) =>
                breakpointMediaQueries(
                    theme,
                    [
                        null,
                        null,
                        null,
                        css`
                            margin-top: 0;
                        `,
                        null,
                    ],
                    "max",
                )}
        `,
    },
    reCaptchaGridItem: {
        width: [12, 12, 12, 12, 4],
        css: css`
            margin-right: -50px !important;
        `,
    },
    reCaptcha: {
        wrapper: {
            css: css`
                margin-top: -3px;
            `,
        },
    },
};

const styles = orderStatusFormStyles;
const StyledForm = getStyledWrapper("form");

const OrderStatusForm = ({
    location,
    history,
    orderNumberFromQuery,
    emailOrPostalCodeFromQuery,
    isAuthenticated,
    isReCaptchaEnabled,
    validateReCaptcha,
}: Props) => {
    const [orderNumber, setOrderNumber] = useState(orderNumberFromQuery);
    const [orderNumberError, setOrderNumberError] = useState<ReactNode>("");
    const [emailOrPostalCode, setEmailOrPostalCode] = useState(emailOrPostalCodeFromQuery);
    const [emailOrPostalCodeError, setEmailOrPostalCodeError] = useState<ReactNode>("");
    const recaptchaRef: RefObject<ReCAPTCHA | null> = React.createRef();

    const orderNumberChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
        setOrderNumber(event.target.value);
        setOrderNumberError(!event.target.value.trim() ? siteMessage("OrderStatusLookup_OrderNumberRequired") : "");
    };

    const emailOrPostalCodeChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
        setEmailOrPostalCode(event.target.value);
        setEmailOrPostalCodeError(
            !event.target.value.trim() ? siteMessage("OrderStatusLookup_EmailOrPostalCodeRequired") : "",
        );
    };

    const handleSubmit = async (event: React.MouseEvent<HTMLFormElement, MouseEvent>) => {
        event.preventDefault();

        const isReCaptchaValid = await validateReCaptcha({ location: "OrderStatus", recaptchaRef });
        if (!isReCaptchaValid) {
            return;
        }

        const paramName = emailOrPostalCode.indexOf("@") >= 0 ? "stEmail" : "stPostalCode";
        history.push(`${location.pathname}?orderNumber=${orderNumber}&${paramName}=${emailOrPostalCode}`);
    };

    return (
        <>
            <StyledForm {...styles.form} onSubmit={handleSubmit}>
                <GridContainer {...styles.gridContainer}>
                    <GridItem {...styles.orderNumberGridItem}>
                        <TextField
                            label={translate("Order Number")}
                            value={orderNumber}
                            onChange={orderNumberChangeHandler}
                            error={orderNumberError}
                            required
                            {...styles.orderNumberTextField}
                            data-test-selector="orderStatusForm_orderNumber"
                        />
                    </GridItem>
                    <GridItem {...styles.emailOrPostalCodeGridItem}>
                        <TextField
                            label={translate("Email Address or Postal Code")}
                            value={emailOrPostalCode}
                            onChange={emailOrPostalCodeChangeHandler}
                            error={emailOrPostalCodeError}
                            required
                            {...styles.emailOrPostalCodeTextField}
                            data-test-selector="orderStatusForm_emailOrPostalCode"
                        />
                    </GridItem>
                    {isReCaptchaEnabled && !isAuthenticated && !getCookie("g-recaptcha-verified") && (
                        <GridItem {...styles.reCaptchaGridItem}>
                            <ReCaptcha
                                recaptchaRef={recaptchaRef}
                                location="OrderStatus"
                                extendedStyles={styles.reCaptcha}
                            />
                        </GridItem>
                    )}
                    <GridItem {...styles.submitButtonGridItem}>
                        <Button
                            {...styles.submitButton}
                            type="submit"
                            disabled={!orderNumber || !emailOrPostalCode}
                            data-test-selector="orderStatusForm_submit"
                        >
                            {translate("Submit")}
                        </Button>
                    </GridItem>
                </GridContainer>
            </StyledForm>
        </>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(withHistory(OrderStatusForm)),
    definition: {
        group: "Order Status",
        displayName: "Form",
        allowedContexts: ["OrderStatusPage"],
    },
};

export default widgetModule;
