import StyledWrapper, { getStyledWrapper } from "@insite/client-framework/Common/StyledWrapper";
import {
    convertDateOnlyStringToDate,
    convertDateToDateOnlyString,
} from "@insite/client-framework/Common/Utilities/DateUtilities";
import getLocalizedDateTime from "@insite/client-framework/Common/Utilities/getLocalizedDateTime";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getSession } from "@insite/client-framework/Store/Context/ContextSelectors";
import loadShipTos from "@insite/client-framework/Store/Data/ShipTos/Handlers/LoadShipTos";
import { getShipTosDataView } from "@insite/client-framework/Store/Data/ShipTos/ShipTosSelectors";
import clearSearch from "@insite/client-framework/Store/Pages/OrderApprovalList/Handlers/ClearSearch";
import updateSearchFields from "@insite/client-framework/Store/Pages/OrderApprovalList/Handlers/UpdateSearchFields";
import updateShipTosSearchFields from "@insite/client-framework/Store/Pages/OrderApprovalList/Handlers/UpdateShipTosSearchFields";
import translate from "@insite/client-framework/Translate";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import WidgetProps from "@insite/client-framework/Types/WidgetProps";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import DatePicker, { DatePickerPresentationProps, DatePickerState } from "@insite/mobius/DatePicker";
import DynamicDropdown, { DynamicDropdownPresentationProps, OptionObject } from "@insite/mobius/DynamicDropdown";
import GridContainer, { GridContainerProps } from "@insite/mobius/GridContainer";
import GridItem, { GridItemProps } from "@insite/mobius/GridItem";
import Select, { SelectPresentationProps } from "@insite/mobius/Select";
import Tag, { horizontalStyles, TagPresentationProps } from "@insite/mobius/Tag";
import TextField, { TextFieldPresentationProps } from "@insite/mobius/TextField";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import VisuallyHidden from "@insite/mobius/VisuallyHidden";
import debounce from "lodash/debounce";
import * as React from "react";
import { useEffect, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const { getShipTosParameter, getOrderApprovalsParameter, filtersOpen } = state.pages.orderApprovalList;
    return {
        filtersOpen,
        shipTosDataView: getShipTosParameter && getShipTosDataView(state, getShipTosParameter),
        getOrderApprovalsParameter,
        getShipTosParameter,
        language: getSession(state).language,
    };
};

const mapDispatchToProps = {
    updateSearchFields,
    clearSearch,
    updateShipTosSearchFields,
    loadShipTos,
};

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

export interface OrderApprovalListFilterStyles {
    container?: GridContainerProps;
    headingGridItem?: GridItemProps;
    heading?: TypographyPresentationProps;
    shipToGridItem?: GridItemProps;
    /** @deprecated Use the `shipToDropdown` property instead. */
    shipToSelect?: SelectPresentationProps;
    orderNumberGridItem?: GridItemProps;
    orderNumberTextField?: TextFieldPresentationProps;
    datesGridItem?: GridItemProps;
    datesContainer?: GridContainerProps;
    dateRangeFieldset?: InjectableCss;
    fromGridItem?: GridItemProps;
    fromDate?: DatePickerPresentationProps;
    toGridItem?: GridItemProps;
    toDate?: DatePickerPresentationProps;
    orderTotalGridItem?: GridItemProps;
    orderTotalContainer?: GridContainerProps;
    orderTotalFieldset?: InjectableCss;
    orderTotalOperatorGridItem?: GridItemProps;
    orderTotalOperatorSelect?: SelectPresentationProps;
    orderTotalAmountGridItem?: GridItemProps;
    orderTotalAmountTextField?: TextFieldPresentationProps;
    appliedFiltersContainer?: InjectableCss;
    appliedFilterTag?: TagPresentationProps;
    buttonsItem?: GridItemProps;
    clearFiltersButton?: ButtonPresentationProps;
    shipToDropdown?: DynamicDropdownPresentationProps;
}

export const filterStyles: OrderApprovalListFilterStyles = {
    container: {
        css: css`
            padding-bottom: 15px;
        `,
    },
    headingGridItem: {
        width: 12,
        css: css`
            padding-bottom: 0;
        `,
    },
    heading: {
        variant: "h5",
        css: css`
            margin: 0;
        `,
    },
    shipToGridItem: { width: [12, 12, 5, 5, 4] },
    orderNumberGridItem: { width: [12, 12, 3, 3, 2] },
    datesGridItem: { width: [12, 12, 6, 4, 4] },
    datesContainer: { gap: 10 },
    dateRangeFieldset: {
        css: css`
            border: none;
            margin: 0;
            padding: 0;
            width: 100%;
        `,
    },
    fromGridItem: { width: 6 },
    toGridItem: { width: 6 },
    appliedFiltersContainer: { css: horizontalStyles },
    buttonsItem: {
        width: 12,
        css: css`
            justify-content: flex-end;
        `,
    },
    clearFiltersButton: {
        variant: "secondary",
        css: css`
            margin-right: 10px;
        `,
    },
    toDate: {
        cssOverrides: {
            formField: css`
                width: 100%;
            `,
        },
    },
    orderTotalGridItem: { width: 12 },
    orderTotalContainer: { gap: 10 },
    orderTotalFieldset: {
        css: css`
            border: none;
            margin: 0;
            padding: 0;
            width: 100%;
        `,
    },
    orderTotalOperatorGridItem: { width: [6, 6, 3, 3, 2] },
    orderTotalAmountGridItem: { width: [6, 6, 3, 3, 2] },
    orderTotalAmountTextField: {
        cssOverrides: {
            formInputWrapper: css`
                margin-top: 32px;
            `,
        },
    },
    fromDate: {
        cssOverrides: {
            formField: css`
                width: 100%;
            `,
        },
    },
};

const StyledDateRangeFieldSet = getStyledWrapper("fieldset");
const StyledOrderTotalFieldSet = getStyledWrapper("fieldset");

export const styles = filterStyles;

const OrderApprovalListFilter = ({
    filtersOpen,
    shipTosDataView,
    getShipTosParameter,
    getOrderApprovalsParameter,
    language,
    updateShipTosSearchFields,
    updateSearchFields,
    clearSearch,
    loadShipTos,
}: Props) => {
    const [orderNumber, setOrderNumber] = useState(getOrderApprovalsParameter.orderNumber || "");
    const [orderTotal, setOrderTotal] = useState(getOrderApprovalsParameter.orderTotal || "");
    const [orderTotalOperator, setOrderTotalOperator] = useState(getOrderApprovalsParameter.orderTotalOperator || "");
    const [selectedShipToId, setSelectedShipToId] = useState(getOrderApprovalsParameter.shipToId || "");
    const [updateTimeoutId, setUpdateTimeoutId] = useState<NodeJS.Timeout | undefined>(undefined);
    const [options, setOptions] = useState<OptionObject[]>([]);
    const [search, setSearch] = useState("");

    useEffect(() => {
        if (shipTosDataView && !shipTosDataView.value && !shipTosDataView.isLoading) {
            loadShipTos(getShipTosParameter);
        } else if (getShipTosParameter?.filter) {
            updateShipTosSearchFields({ ...getShipTosParameter, filter: undefined });
        }
    }, []);

    useEffect(() => {
        if (shipTosDataView?.value) {
            const options: OptionObject[] = shipTosDataView.value.map(shipTo => ({
                optionText: shipTo.label,
                optionValue: shipTo.id,
            }));
            setOptions(options);
        }
    }, [shipTosDataView]);

    useEffect(() => {
        if (!shipTosDataView?.isLoading) {
            loadShipTos(getShipTosParameter);
        }
    }, [getShipTosParameter]);

    useEffect(() => {
        setSearch("");
        debouncedUpdateSearchFields("");
    }, [getOrderApprovalsParameter]);

    useEffect(() => {
        if (shipTosDataView?.value) {
            const id = shipTosDataView.value.find(o => o.id === (getOrderApprovalsParameter.shipToId || ""))?.id;
            id && setSelectedShipToId(id);
        }
    }, [getOrderApprovalsParameter.shipToId]);

    useEffect(() => {
        updateParameterAfterTimeout();
    }, [orderNumber, orderTotal, orderTotalOperator]);

    const updateParameterAfterTimeout = () => {
        clearTimeout(updateTimeoutId);

        setUpdateTimeoutId(
            setTimeout(() => {
                const setOrderTotalFilter = orderTotal && orderTotalOperator;
                updateSearchFields({
                    orderNumber,
                    orderTotalOperator: setOrderTotalFilter ? orderTotalOperator : "",
                    orderTotal: setOrderTotalFilter ? orderTotal : "",
                });
            }, 250),
        );
    };

    const selectShipToHandler = (id?: string) => {
        const shipToId = shipTosDataView?.value?.find(o => o.id === id)?.id;
        updateSearchFields({ shipToId });
    };

    const debouncedUpdateSearchFields = debounce((value: string) => {
        updateShipTosSearchFields({ ...getShipTosParameter, filter: value || undefined });
    }, 100);

    const changeSearchTextHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
        const value = event.currentTarget.value;
        setSearch(value);
        debouncedUpdateSearchFields(value);
    };

    const shipToRemoveHandler = () => {
        setSelectedShipToId("");
        updateSearchFields({ shipToId: "" });
    };

    const orderNumberChangeHandler = (value: string) => {
        setOrderNumber(value);
    };

    const fromDateChangeHandler = ({ selectedDay }: Pick<DatePickerState, "selectedDay">) => {
        updateSearchFields({
            fromDate: convertDateToDateOnlyString(selectedDay),
        });
    };

    const toDateChangeHandler = ({ selectedDay }: Pick<DatePickerState, "selectedDay">) => {
        updateSearchFields({
            toDate: convertDateToDateOnlyString(selectedDay),
        });
    };

    const orderTotalOperatorChangeHandler = (value: string) => {
        setOrderTotalOperator(value);
    };

    const orderTotalChangeHandler = (value: string) => {
        setOrderTotal(value);
    };

    const clearFiltersClickHandler = () => {
        setOrderNumber("");
        setOrderTotalOperator("");
        setOrderTotal("");
        setSelectedShipToId("");
        clearSearch();
    };

    const { fromDate, toDate } = getOrderApprovalsParameter;
    if (!filtersOpen) {
        const selectedShipTo = options.find(o => o.optionValue === selectedShipToId);

        return (
            <StyledWrapper {...styles.appliedFiltersContainer}>
                {selectedShipTo && (
                    <Tag
                        {...styles.appliedFilterTag}
                        data-test-selector="orderApproval_shipToAddress_whenCollapsed"
                        onDelete={() => {
                            shipToRemoveHandler();
                        }}
                    >
                        {`${translate("Ship to Address")}: ${selectedShipTo.optionText}`}
                    </Tag>
                )}
                {orderNumber && (
                    <Tag
                        {...styles.appliedFilterTag}
                        onDelete={() => {
                            orderNumberChangeHandler("");
                        }}
                    >
                        {`${translate("Order #")}: ${orderNumber}`}
                    </Tag>
                )}
                {fromDate && (
                    <Tag
                        {...styles.appliedFilterTag}
                        onDelete={() => {
                            fromDateChangeHandler({});
                        }}
                    >
                        {`${translate("From")}: ${getLocalizedDateTime({
                            dateTime: convertDateOnlyStringToDate(fromDate)!,
                            language,
                        })}`}
                    </Tag>
                )}
                {toDate && (
                    <Tag
                        {...styles.appliedFilterTag}
                        onDelete={() => {
                            toDateChangeHandler({});
                        }}
                    >
                        {`${translate("To")}: ${getLocalizedDateTime({
                            dateTime: convertDateOnlyStringToDate(toDate)!,
                            language,
                        })}`}
                    </Tag>
                )}
                {orderTotalOperator && orderTotal && (
                    <Tag
                        {...styles.appliedFilterTag}
                        onDelete={() => {
                            orderTotalOperatorChangeHandler("");
                            orderTotalChangeHandler("");
                        }}
                    >
                        {`${translate("Order Total")}: ${orderTotalOperator} ${orderTotal}`}
                    </Tag>
                )}
            </StyledWrapper>
        );
    }

    const fromDateObj = convertDateOnlyStringToDate(getOrderApprovalsParameter.fromDate);
    const toDateObj = convertDateOnlyStringToDate(getOrderApprovalsParameter.toDate);

    return (
        <GridContainer {...styles.container}>
            <GridItem {...styles.headingGridItem}>
                <Typography {...styles.heading} as="h2">
                    {translate("Filter")}
                </Typography>
            </GridItem>
            <GridItem {...styles.shipToGridItem}>
                <DynamicDropdown
                    {...styles.shipToDropdown}
                    label={translate("Ship To")}
                    onSelectionChange={selectShipToHandler}
                    onInputChange={changeSearchTextHandler}
                    selected={selectedShipToId}
                    isLoading={shipTosDataView?.isLoading}
                    options={options}
                    search={search}
                    data-test-selector="orderApproval_shipToAddress"
                    filterOption={() => true}
                />
            </GridItem>
            <GridItem {...styles.orderNumberGridItem}>
                <TextField
                    {...styles.orderNumberTextField}
                    value={orderNumber}
                    label={translate("Order #")}
                    data-test-selector="orderApproval_orderNumberFilter"
                    onChange={event => orderNumberChangeHandler(event.target.value)}
                />
            </GridItem>
            <GridItem {...styles.datesGridItem}>
                <StyledDateRangeFieldSet {...styles.dateRangeFieldset}>
                    <VisuallyHidden as="label">{translate("Date Range")}</VisuallyHidden>
                    <GridContainer {...styles.datesContainer}>
                        <GridItem data-test-selector="orderApproval_fromDateFilter" {...styles.fromGridItem}>
                            <DatePicker
                                {...styles.fromDate}
                                label={translate("From")}
                                selectedDay={fromDateObj}
                                onDayChange={fromDateChangeHandler}
                                dateTimePickerProps={{
                                    clearIcon: null,
                                    maxDate: toDateObj,
                                    ...styles.fromDate?.dateTimePickerProps,
                                }}
                            />
                        </GridItem>
                        <GridItem data-test-selector="orderApproval_toDateFilter" {...styles.toGridItem}>
                            <DatePicker
                                {...styles.toDate}
                                label={translate("To")}
                                selectedDay={toDateObj}
                                onDayChange={toDateChangeHandler}
                                dateTimePickerProps={{
                                    clearIcon: null,
                                    minDate: fromDateObj,
                                    ...styles.toDate?.dateTimePickerProps,
                                }}
                            />
                        </GridItem>
                    </GridContainer>
                </StyledDateRangeFieldSet>
            </GridItem>
            <GridItem {...styles.orderTotalGridItem}>
                <StyledOrderTotalFieldSet {...styles.orderTotalFieldset}>
                    <VisuallyHidden as="label">{translate("Order Total")}</VisuallyHidden>
                    <GridContainer {...styles.orderTotalContainer}>
                        <GridItem {...styles.orderTotalOperatorGridItem}>
                            <Select
                                {...styles.orderTotalOperatorSelect}
                                label={translate("Order Total")}
                                value={orderTotalOperator || ""}
                                data-test-selector="orderApproval_comparisonMethod"
                                onChange={event => orderTotalOperatorChangeHandler(event.target.value)}
                            >
                                <option value="">{translate("Select")}</option>
                                <option key="Greater Than" value="Greater Than">
                                    {translate("Greater Than")}
                                </option>
                                <option key="Less Than" value="Less Than">
                                    {translate("Less Than")}
                                </option>
                                <option key="Equal To" value="Equal To">
                                    {translate("Equal To")}
                                </option>
                            </Select>
                        </GridItem>
                        <GridItem {...styles.orderTotalAmountGridItem}>
                            <TextField
                                {...styles.orderTotalAmountTextField}
                                value={orderTotal || ""}
                                data-test-selector="orderApproval_comparisonValue"
                                onChange={event => orderTotalChangeHandler(event.target.value)}
                            />
                        </GridItem>
                    </GridContainer>
                </StyledOrderTotalFieldSet>
            </GridItem>
            <GridItem {...styles.buttonsItem}>
                <Button
                    {...styles.clearFiltersButton}
                    data-test-selector="orderApproval_clearFiltersButton"
                    onClick={clearFiltersClickHandler}
                >
                    {translate("Clear Filters")}
                </Button>
            </GridItem>
        </GridContainer>
    );
};

const widgetModule: WidgetModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(OrderApprovalListFilter),
    definition: {
        group: "Order Approval List",
        displayName: "Search Results Filter",
        allowedContexts: ["OrderApprovalListPage"],
        isSystem: true,
    },
};

export default widgetModule;
