import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import addDays from "@insite/client-framework/Common/Utilities/addDays";
import { FulfillmentMethod } from "@insite/client-framework/Services/SessionService";
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 { getCartState, getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getPageLinkByPageType } from "@insite/client-framework/Store/Links/LinksSelectors";
import setRequestedDeliveryDate from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetRequestedDeliveryDate";
import setRequestedPickUpDate from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetRequestedPickUpDate";
import setShippingMethod from "@insite/client-framework/Store/Pages/OnePageCheckout/Handlers/SetShippingMethod";
import translate from "@insite/client-framework/Translate";
import { ShipViaDto } from "@insite/client-framework/Types/ApiModels";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import DatePicker, { DatePickerPresentationProps, DatePickerState } from "@insite/mobius/DatePicker";
import GridContainer, { GridContainerProps } from "@insite/mobius/GridContainer";
import GridItem, { GridItemProps } from "@insite/mobius/GridItem";
import Link, { LinkPresentationProps } from "@insite/mobius/Link";
import LoadingSpinner from "@insite/mobius/LoadingSpinner";
import Radio, { RadioPresentationProps } from "@insite/mobius/Radio";
import RadioGroup, { RadioGroupPresentationProps } from "@insite/mobius/RadioGroup";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import flatMap from "lodash/flatMap";
import React, { ChangeEvent, useEffect, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const {
        accountSettings: { enableWarehousePickup, allowEmptyShipping },
        cartSettings: { canRequestDeliveryDate, enableRequestPickUpDate, maximumDeliveryPeriod },
    } = getSettingsCollection(state);
    const { fulfillmentMethod, pickUpWarehouse } = state.context.session;
    const { cartId } = state.pages.onePageCheckout;
    const cartState = cartId ? getCartState(state, cartId) : getCurrentCartState(state);
    const { value: cart, isLoading: isCartLoading } = cartState;
    return {
        cart,
        isCartLoading,
        showShippingMethod: fulfillmentMethod === FulfillmentMethod.Ship,
        showRequestPickUpDate:
            enableWarehousePickup && enableRequestPickUpDate && fulfillmentMethod === FulfillmentMethod.PickUp,
        showRequestDeliveryDate: canRequestDeliveryDate,
        maximumDeliveryPeriod,
        cartUrl: getPageLinkByPageType(state, "CartPage")?.url,
        pickUpWarehouse,
        allowEmptyShipping,
    };
};

const mapDispatchToProps = {
    setShippingMethod,
    setRequestedDeliveryDate,
    setRequestedPickUpDate,
};

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

export interface OnePageCheckoutDeliveryMethodStyles {
    container?: GridContainerProps;
    centeringWrapper?: InjectableCss;
    titleGridItem?: GridItemProps;
    titleText?: TypographyPresentationProps;
    editGridItem?: GridItemProps;
    editLink?: LinkPresentationProps;
    fulfillmentMethodGridItem?: GridItemProps;
    fulfillmentMethodText?: TypographyPresentationProps;
    noCarriersFoundGridItem?: GridItemProps;
    noCarriersFoundText?: TypographyPresentationProps;
    servicesGridItem?: GridItemProps;
    servicesRadioGroup?: RadioGroupPresentationProps;
    serviceRadio?: RadioPresentationProps;
    deliveryDateGridItem?: GridItemProps;
    deliveryDatePicker?: DatePickerPresentationProps;
    pickUpDateGridItem?: GridItemProps;
    pickUpDatePicker?: DatePickerPresentationProps;
}

export const onePageCheckoutDeliveryMethodStyles: OnePageCheckoutDeliveryMethodStyles = {
    container: { gap: 20 },
    centeringWrapper: {
        css: css`
            display: flex;
            justify-content: center;
            align-items: center;
            height: 450px;
        `,
    },
    titleGridItem: {
        width: 10,
        css: css`
            align-items: center;
        `,
    },
    titleText: {
        variant: "h5",
        transform: "capitalize",
        css: css`
            margin-bottom: 0;
        `,
    },
    editGridItem: {
        width: 2,
        css: css`
            justify-content: end;
            align-items: center;
        `,
    },
    fulfillmentMethodGridItem: { width: 12 },
    fulfillmentMethodText: {
        variant: "h6",
        css: css`
            margin-bottom: 0;
        `,
    },
    noCarriersFoundGridItem: { width: 12 },
    servicesGridItem: { width: 12 },
    deliveryDateGridItem: { width: 12 },
    pickUpDateGridItem: { width: 12 },
};

const styles = onePageCheckoutDeliveryMethodStyles;

const OnePageCheckoutDeliveryMethod = ({
    cart,
    isCartLoading,
    cartUrl,
    pickUpWarehouse,
    showShippingMethod,
    showRequestPickUpDate,
    showRequestDeliveryDate,
    maximumDeliveryPeriod,
    setRequestedDeliveryDate,
    setRequestedPickUpDate,
    setShippingMethod,
    allowEmptyShipping,
}: Props) => {
    const [selectedShipVia, setSelectedShipVia] = useState<ShipViaDto | null>(null);
    const [isUpdatingCart, setIsUpdatingCart] = useState(false);
    useEffect(() => {
        if (cart) {
            setSelectedShipVia(cart.shipVia);
            setIsUpdatingCart(false);
        }
    }, [cart?.carrier, cart?.shipVia]);

    if (!cart || (cart.lineCount && (!cart.cartLines || cart.cartLines.length === 0)) || !cart.carriers) {
        return (
            <StyledWrapper {...styles.centeringWrapper}>
                <LoadingSpinner data-test-selector="onePageCheckout_deliveryMethodLoading" />
            </StyledWrapper>
        );
    }

    const serviceChangeHandler = (event: ChangeEvent<HTMLInputElement>) => {
        if (!cart.carriers) {
            return;
        }

        const shipVias = flatMap(cart.carriers, o => o.shipVias).filter(o => !!o) as ShipViaDto[];
        const shipVia = shipVias.find(o => o.id === event.currentTarget.value);
        if (!shipVia) {
            return;
        }

        const carrier = cart.carriers.find(o => o.shipVias?.some(p => p.id === shipVia.id));
        if (!carrier) {
            return;
        }

        setIsUpdatingCart(true);
        setSelectedShipVia(shipVia);
        setShippingMethod({ carrier, shipVia });
    };

    const handleRequestPickUpDateChanged = ({ selectedDay, selectedDayDisabled }: DatePickerState) => {
        setRequestedPickUpDate({
            requestedPickUpDate: selectedDay,
            requestedPickUpDateDisabled: selectedDayDisabled,
        });
    };
    const handleRequestDeliveryDateChanged = ({ selectedDay, selectedDayDisabled }: DatePickerState) => {
        setRequestedDeliveryDate({
            requestedDeliveryDate: selectedDay,
            requestedDeliveryDateDisabled: selectedDayDisabled,
        });
    };

    return (
        <GridContainer {...styles.container}>
            <GridItem {...styles.titleGridItem}>
                <Typography as="h2" {...styles.titleText}>
                    {translate("Delivery method")}
                </Typography>
            </GridItem>
            <GridItem {...styles.editGridItem}>
                <Link {...styles.editLink} href={cartUrl}>
                    {translate("Edit")}
                </Link>
            </GridItem>
            <GridItem {...styles.fulfillmentMethodGridItem}>
                <Typography
                    as="p"
                    {...styles.fulfillmentMethodText}
                    data-test-selector="onePageCheckout_fulfillmentMethod"
                >
                    {showShippingMethod
                        ? translate("Ship to home")
                        : `${translate("Store pickup at")} ${pickUpWarehouse?.description || pickUpWarehouse?.name}`}
                </Typography>
            </GridItem>
            {showShippingMethod && (
                <>
                    {cart.carriers?.length === 0 && !allowEmptyShipping && (
                        <GridItem {...styles.noCarriersFoundGridItem}>
                            <Typography {...styles.noCarriersFoundText}>
                                {siteMessage("ReviewAndPay_NoCarriersFound")}
                            </Typography>
                        </GridItem>
                    )}
                    {cart.carriers.length > 0 && (
                        <GridItem {...styles.servicesGridItem}>
                            <RadioGroup
                                {...styles.servicesRadioGroup}
                                label={translate("Choose delivery method:")}
                                value={selectedShipVia?.id}
                                disabled={isCartLoading || isUpdatingCart}
                                onChangeHandler={serviceChangeHandler}
                                data-test-selector="onePageCheckout_chooseDeliveryMethod"
                            >
                                {flatMap(cart.carriers, carrier =>
                                    carrier.shipVias?.map(shipVia => ({ ...shipVia, carrier })),
                                ).map(shipVia => (
                                    <Radio {...styles.serviceRadio} key={shipVia?.id} value={shipVia?.id}>
                                        {shipVia?.carrier.description} - {shipVia?.description}
                                    </Radio>
                                ))}
                            </RadioGroup>
                        </GridItem>
                    )}
                    {showRequestDeliveryDate && (
                        <GridItem
                            {...styles.deliveryDateGridItem}
                            data-test-selector="onePageCheckout_requestedDeliveryDate"
                        >
                            <DatePicker
                                {...styles.deliveryDatePicker}
                                label={`${translate("Request Delivery Date")} (${translate("optional")})`}
                                hint={siteMessage("Checkout_RequestedDeliveryDateInformation")}
                                selectedDay={cart.requestedDeliveryDateDisplay!}
                                dateTimePickerProps={{
                                    minDate: new Date(),
                                    maxDate: addDays(new Date(), maximumDeliveryPeriod),
                                    monthAriaLabel: translate("Request delivery date month"),
                                    dayAriaLabel: translate("Request delivery date day"),
                                    yearAriaLabel: translate("Request delivery date year"),
                                    ...styles.deliveryDatePicker?.dateTimePickerProps,
                                }}
                                onDayChange={handleRequestDeliveryDateChanged}
                            />
                        </GridItem>
                    )}
                </>
            )}
            {showRequestPickUpDate && (
                <GridItem {...styles.pickUpDateGridItem} data-test-selector="onePageCheckout_requestPickUpDate">
                    <DatePicker
                        {...styles.pickUpDatePicker}
                        label={`${translate("Request Pick Up Date")} (${translate("optional")})`}
                        hint={siteMessage("Checkout_RequestedPickupDateInformation")}
                        selectedDay={cart.requestedPickupDateDisplay!}
                        dateTimePickerProps={{
                            minDate: new Date(),
                            maxDate: addDays(new Date(), maximumDeliveryPeriod),
                            ...styles.pickUpDatePicker?.dateTimePickerProps,
                        }}
                        onDayChange={handleRequestPickUpDateChanged}
                        monthAriaLabel={`${translate("Request Pick Up Date optional")}. ${translate(
                            "Enter month, format M M",
                        )}`}
                        dayAriaLabel={`${translate("Request Pick Up Date optional")}. ${translate(
                            "Enter day, format D D",
                        )}`}
                        yearAriaLabel={`${translate("Request Pick Up Date optional")}. ${translate(
                            "Enter year, format Y Y Y Y",
                        )}`}
                    />
                </GridItem>
            )}
        </GridContainer>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(OnePageCheckoutDeliveryMethod),
    definition: {
        displayName: "Delivery Method",
        group: "One Page Checkout",
        allowedContexts: ["OnePageCheckoutPage"],
    },
};

export default widgetModule;
