import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import { SafeDictionary } from "@insite/client-framework/Common/Types";
import getFileExtension from "@insite/client-framework/Common/Utilities/getFileExtension";
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 batchLoadProducts, {
    UploadError,
} from "@insite/client-framework/Store/Components/OrderUpload/Handlers/BatchLoadProducts";
import cleanupUploadData from "@insite/client-framework/Store/Components/OrderUpload/Handlers/CleanupUploadData";
import { OrderUploadRowError } from "@insite/client-framework/Store/Components/OrderUpload/OrderUploadState";
import processFile from "@insite/client-framework/Store/Components/VmiCountsImportModal/Handlers/ProcessFile";
import setIsBadFile from "@insite/client-framework/Store/Components/VmiCountsImportModal/Handlers/SetIsBadFile";
import setIsUploading from "@insite/client-framework/Store/Components/VmiCountsImportModal/Handlers/SetIsUploading";
import setUploadLimitExceeded from "@insite/client-framework/Store/Components/VmiCountsImportModal/Handlers/SetUploadLimitExceeded";
import setVmiCountsImportModalIsOpen from "@insite/client-framework/Store/Components/VmiCountsImportModal/Handlers/SetVmiCountsImportModalIsOpen";
import { getLocation } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import loadVmiBins from "@insite/client-framework/Store/Data/VmiBins/Handlers/LoadVmiBins";
import { getVmiBinsDataView } from "@insite/client-framework/Store/Data/VmiBins/VmiBinsSelectors";
import addVmiCounts from "@insite/client-framework/Store/Data/VmiCounts/Handlers/AddVmiCounts";
import { VmiLocationStateContext } from "@insite/client-framework/Store/Data/VmiLocations/VmiLocationsSelectors";
import translate from "@insite/client-framework/Translate";
import { VmiCountModel } from "@insite/client-framework/Types/ApiModels";
import Button, { ButtonPresentationProps } from "@insite/mobius/Button";
import DataTable, { DataTableProps } from "@insite/mobius/DataTable";
import DataTableBody, { DataTableBodyProps } from "@insite/mobius/DataTable/DataTableBody";
import DataTableCell from "@insite/mobius/DataTable/DataTableCell";
import { DataTableCellBaseProps } from "@insite/mobius/DataTable/DataTableCellBase";
import DataTableHead, { DataTableHeadProps } from "@insite/mobius/DataTable/DataTableHead";
import DataTableHeader, { DataTableHeaderProps } from "@insite/mobius/DataTable/DataTableHeader";
import DataTableRow, { DataTableRowProps } from "@insite/mobius/DataTable/DataTableRow";
import FileUpload, { FileUploadPresentationProps } from "@insite/mobius/FileUpload";
import GridContainer, { GridContainerProps } from "@insite/mobius/GridContainer";
import GridItem, { GridItemProps } from "@insite/mobius/GridItem";
import Link, { LinkPresentationProps } from "@insite/mobius/Link";
import Modal, { ModalPresentationProps } from "@insite/mobius/Modal";
import { HasToasterContext, withToaster } from "@insite/mobius/Toast/ToasterContext";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import React, { useContext, useEffect, useRef, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const location = getLocation(state);
    const parsedQuery = parseQueryString<{ locationId?: string }>(location.search);
    const getVmiBinsParameter = {
        vmiLocationId: parsedQuery?.locationId,
        page: 1,
        pageSize: 9999,
    };
    return {
        parsedQuery,
        parsedItems: state.components.vmiCountsImportModal.parsedItems,
        isUploading: state.components.vmiCountsImportModal.isUploading,
        uploadLimitExceeded: state.components.vmiCountsImportModal.uploadLimitExceeded,
        isOpen: state.components.vmiCountsImportModal.modalIsOpen,
        isBadFile: state.components.vmiCountsImportModal.isBadFile,
        products: state.components.orderUpload.products,
        rowErrors: state.components.orderUpload.rowErrors,
        productsProcessed: state.components.orderUpload.productsProcessed,
        vmiBinsDataView: getVmiBinsDataView(state, getVmiBinsParameter),
        getVmiBinsParameter,
    };
};

const mapDispatchToProps = {
    processFile,
    cleanupUploadData,
    batchLoadProducts,
    setUploadLimitExceeded,
    setIsBadFile,
    setIsUploading,
    setVmiCountsImportModalIsOpen,
    addVmiCounts,
    loadVmiBins,
};

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

export interface VmiCountsImportModalStyles {
    modal?: ModalPresentationProps;
    container?: GridContainerProps;

    textGridItem?: GridItemProps;
    instructionText?: TypographyPresentationProps;
    templateLink?: LinkPresentationProps;
    controlsGridItem?: GridItemProps;
    fileUploader?: FileUploadPresentationProps;

    buttonsGridItem?: GridItemProps;
    cancelButton?: ButtonPresentationProps;
    importButton?: ButtonPresentationProps;

    dataTable?: DataTableProps;
    tableHead?: DataTableHeadProps;
    itemNumHeader?: DataTableHeaderProps;
    itemNameHeader?: DataTableHeaderProps;
    itemReasonHeader?: DataTableHeaderProps;
    tableBody?: DataTableBodyProps;
    tableRow?: DataTableRowProps;
    itemNumCell?: DataTableCellBaseProps;
    itemNameCell?: DataTableCellBaseProps;
    itemReasonCell?: DataTableCellBaseProps;

    errorLineHeader?: DataTableHeaderProps;
    errorLineCell?: DataTableCellBaseProps;

    tableWrapper?: InjectableCss;
}

export const vmiCountsImportModalStyles: VmiCountsImportModalStyles = {
    modal: {
        cssOverrides: {
            modalBody: css`
                overflow: visible;
            `,
        },
    },
    container: { gap: 15 },
    controlsGridItem: {
        width: 12,
        css: css`
            display: block;
            max-width: 450px;
            padding-bottom: 40px;
        `,
    },
    textGridItem: {
        width: 12,
        css: css`
            flex-direction: column;
        `,
    },
    instructionText: {
        css: css`
            margin-bottom: 12px;
        `,
    },
    fileUploader: {
        buttonProps: {
            variant: "tertiary",
        },
    },
    buttonsGridItem: {
        css: css`
            justify-content: flex-end;
        `,
        width: 12,
    },
    cancelButton: { variant: "tertiary" },
    importButton: {
        css: css`
            margin-left: 1rem;
        `,
    },
    tableRow: {
        css: css`
            td {
                white-space: normal;
            }
        `,
    },
    tableWrapper: {
        css: css`
            max-height: 400px;
            overflow-y: auto;
            width: 100%;
        `,
    },
};

const styles = vmiCountsImportModalStyles;

const VmiCountsImportModal = ({
    isOpen,
    toaster,
    parsedQuery,
    parsedItems,
    isUploading,
    products,
    rowErrors,
    isBadFile,
    productsProcessed,
    uploadLimitExceeded,
    processFile,
    cleanupUploadData,
    batchLoadProducts,
    setUploadLimitExceeded,
    setIsBadFile,
    setIsUploading,
    setVmiCountsImportModalIsOpen,
    addVmiCounts,
    loadVmiBins,
    getVmiBinsParameter,
    vmiBinsDataView,
}: Props) => {
    const fileUploadRef = useRef({ value: "" } as HTMLInputElement);

    const [file, setFile] = useState<any>(null);
    const [incorrectFileExtension, setIncorrectFileExtension] = React.useState(false);
    const [errorMessages, setErrorMessages] = useState<string[]>([]);
    const [binCountsErrors, setBinCountsError] = useState<OrderUploadRowError[]>([]);
    const [continueImport, setContinueImport] = useState<boolean>(false);
    const [dataToImport, setDataToImport] = useState<VmiCountModel[]>([]);
    const [hasImportErrors, setHasImportErrors] = useState<boolean>(false);
    const { value: vmiLocation } = useContext(VmiLocationStateContext);
    const vmiLocationId = vmiLocation?.id || parsedQuery?.locationId;
    const vmiBins = vmiBinsDataView.value;

    useEffect(() => batchGetProducts(), [parsedItems]);

    useEffect(() => processImport(), [productsProcessed, isOpen]);

    useEffect(() => {
        if (!isOpen) {
            resetState();
            cleanUp();
        }
    }, [isOpen]);

    useEffect(() => {
        if (isOpen && !vmiBinsDataView.value && !vmiBinsDataView.isLoading) {
            loadVmiBins(getVmiBinsParameter);
        }
    }, [getVmiBinsParameter]);

    const resetState = () => {
        setFile(null);
        setIncorrectFileExtension(false);
        setErrorMessages([]);
        setBinCountsError([]);
        setContinueImport(false);
        setDataToImport([]);
        setUploadLimitExceeded({ uploadLimitExceeded: false });
        setIsBadFile({ isBadFile: false });
    };

    const closeModalHandler = (isCancel = false) => {
        setIsUploading({ isUploading: false });
        setContinueImport(false);

        if (isCancel) {
            if ((rowErrors && rowErrors.length > 0) || binCountsErrors.length > 0) {
                cleanUp();
                return;
            }

            if (errorMessages.length > 0) {
                setErrorMessages([]);
                return;
            }
        }

        setVmiCountsImportModalIsOpen({ modalIsOpen: false });
    };

    const cleanUp = () => {
        cleanupUploadData();
        setBinCountsError([]);
    };

    const batchGetProducts = () => {
        cleanupUploadData();
        if (!file) {
            return;
        }

        if (parsedItems.length === 0) {
            setIsBadFile({ isBadFile: true });
            return;
        }

        const extendedNames = parsedItems.map(item => item.name);
        batchLoadProducts({ extendedNames, firstRowHeading: false, checkInventory: false });
    };

    const fileChangeHandler = (event: React.ChangeEvent<any>) => {
        setIsUploading({ isUploading: false });
        const uploadedFile = event.target.files[0];
        setFile(uploadedFile);
        if (uploadedFile) {
            const fileExtension = getFileExtension(uploadedFile.name);
            const incorrectFileExtension = ["csv"].indexOf(fileExtension) === -1;
            setIncorrectFileExtension(incorrectFileExtension);
            setIsBadFile({ isBadFile: incorrectFileExtension });
            setUploadLimitExceeded({ uploadLimitExceeded: false });
        }
    };

    const onImportClick = () => {
        const reader = new FileReader();
        reader.onload = onReaderLoad(getFileExtension(file.name));
        reader.readAsArrayBuffer(file);
    };

    const onReaderLoad = (fileExtension: string) => {
        return (e: Event) => {
            const data = (e.target as any).result;
            processFile({ data, fileExtension });
        };
    };

    const processImport = React.useCallback(() => {
        if (!productsProcessed || !isOpen) {
            return;
        }

        if (parsedItems.length > 0) {
            importCounts();
        } else {
            setIsUploading({ isUploading: false });
        }
    }, [productsProcessed, parsedItems, rowErrors, isOpen]);

    const importCounts = () => {
        if (!vmiLocationId) {
            return;
        }
        const erpNumberToIdMap: SafeDictionary<string> = {};
        const vmiCounts: VmiCountModel[] = [];

        let importRowErrors = rowErrors.map(error => ({ ...error }));
        for (const product of products) {
            if (product.erpNumber) {
                erpNumberToIdMap[product.erpNumber.toLowerCase()] = product.id;
            }

            if (product.customerName) {
                erpNumberToIdMap[product.customerName.toLowerCase()] = product.id;
            }
        }

        const regexp = /^\d{0,13}(\.\d{1,5})?$/; // regex for decimal(18,5)
        let index = 0;
        for (const item of parsedItems) {
            index++;
            if (!item.name) {
                importRowErrors.push({
                    index,
                    error: UploadError.ProductRequired,
                    name: item.name,
                    qtyRequested: 0,
                });
            }

            const vmiBin = vmiBins?.find(bin => bin.binNumber.toLowerCase() === item.binNumber.toLowerCase());
            if (vmiBin) {
                if (vmiBin.product.erpNumber !== item.name && item.name) {
                    importRowErrors.push({
                        index,
                        error: UploadError.MisMatch,
                        name: item.name,
                        qtyRequested: 0,
                    });
                }
                if (!item.count) {
                    importRowErrors.push({
                        index,
                        error: UploadError.CountNotProvided,
                        name: item.name,
                        qtyRequested: 0,
                    });
                } else if (!item.count || !regexp.test(item.count.toString())) {
                    importRowErrors.push({
                        index,
                        error: UploadError.WrongType,
                        name: item.name,
                        qtyRequested: 0,
                    });
                } else if (+item.count < 0) {
                    importRowErrors.push({
                        index,
                        error: UploadError.BinNegativeCount,
                        name: item.name,
                        qtyRequested: 0,
                    });
                } else {
                    const productId = erpNumberToIdMap[item.name.toLowerCase()];
                    if (vmiBin.id && productId) {
                        vmiCounts.push({
                            vmiBinId: vmiBin.id,
                            productId,
                            Count: item.count,
                        } as unknown as VmiCountModel);
                    }
                }
            } else {
                importRowErrors.push({
                    index,
                    error: UploadError.BinNotFound,
                    name: item.binNumber,
                    qtyRequested: 0,
                });
            }
        }
        importRowErrors = importRowErrors.sort((a, b) => (a.index < b.index ? -1 : 1));
        setBinCountsError(importRowErrors);
        setDataToImport(vmiCounts);
        const hasErrors = (importRowErrors && importRowErrors.length > 0) || errorMessages.length > 0;
        setHasImportErrors(hasErrors);

        if (hasErrors && !continueImport) {
            setContinueImport(true);
            return;
        }

        addVmiCounts({
            vmiLocationId,
            vmiCounts,
            onComplete: result => {
                setIsUploading({ isUploading: false });
                if (result.apiResult?.successful) {
                    setVmiCountsImportModalIsOpen({ modalIsOpen: false });
                    toaster.addToast({
                        body: translate(`${vmiCounts.length} ${vmiCounts.length > 1 ? "items" : "item"} imported`),
                        messageType: "success",
                    });
                } else if (result.apiResult?.errorMessage) {
                    setErrorMessages(result.apiResult?.errorMessage.split("\r\n"));
                }
            },
        });
    };

    if (!vmiLocationId) {
        return null;
    }
    return (
        <Modal
            {...styles.modal}
            handleClose={() => closeModalHandler()}
            headline={translate(hasImportErrors ? "Import Errors" : "Import Counts")}
            isOpen={isOpen}
            size={600}
        >
            <GridContainer {...styles.container}>
                {(!binCountsErrors || binCountsErrors.length === 0) && errorMessages.length === 0 && (
                    <>
                        <GridItem {...styles.textGridItem}>
                            <Typography as="p" {...styles.instructionText}>
                                {siteMessage("Vmi_CountsImportInstructions_Line1")}
                            </Typography>
                            <Typography as="p" {...styles.instructionText}>
                                {siteMessage("Vmi_CountsImportInstructions_Line2")}
                            </Typography>
                            <Typography as="p" {...styles.instructionText}>
                                <Link href="/Excel/VMIImport_counts.csv" target="_blank" {...styles.templateLink}>
                                    {translate("Download CSV File")}
                                </Link>
                            </Typography>
                        </GridItem>
                        <GridItem {...styles.controlsGridItem}>
                            <FileUpload
                                {...styles.fileUploader}
                                inputRef={fileUploadRef}
                                fileName={file?.name || ""}
                                accept=".csv"
                                label={translate("Choose File")}
                                labelPosition="top"
                                error={
                                    incorrectFileExtension
                                        ? translate("only .csv is supported")
                                        : uploadLimitExceeded
                                        ? siteMessage("Vmi_CountsImportRowsLimitExceeded")
                                        : isBadFile
                                        ? siteMessage("Vmi_CountsImportUploadError")
                                        : undefined
                                }
                                onFileChange={fileChangeHandler}
                                uid="vmiCountUploadFileUpload"
                            />
                        </GridItem>
                    </>
                )}
                {binCountsErrors && binCountsErrors.length > 0 && errorMessages.length === 0 && (
                    <StyledWrapper {...styles.tableWrapper}>
                        <DataTable {...styles.dataTable}>
                            <DataTableHead {...styles.tableHead}>
                                <DataTableHeader {...styles.itemNumHeader}>{translate("Row")}</DataTableHeader>
                                <DataTableHeader {...styles.itemNameHeader}>{translate("Item #")}</DataTableHeader>
                                <DataTableHeader {...styles.itemReasonHeader}>{translate("Reason")}</DataTableHeader>
                            </DataTableHead>
                            <DataTableBody {...styles.tableBody}>
                                {binCountsErrors.map(({ index, name, error, message }) => (
                                    <DataTableRow key={index} {...styles.tableRow}>
                                        <DataTableCell {...styles.itemNumCell}>{index}</DataTableCell>
                                        <DataTableCell {...styles.itemNameCell}>{name}</DataTableCell>
                                        <DataTableCell {...styles.itemReasonCell}>
                                            {error === UploadError.NotEnough &&
                                                siteMessage("QuickOrder_NotEnoughQuantity")}
                                            {error === UploadError.ConfigurableProduct &&
                                                siteMessage("QuickOrder_CannotOrderConfigurable")}
                                            {error === UploadError.StyledProduct &&
                                                siteMessage("QuickOrder_CannotOrderStyled")}
                                            {error === UploadError.Unavailable &&
                                                siteMessage("QuickOrder_ProductIsUnavailable")}
                                            {error === UploadError.InvalidUnit && translate("Invalid U/M")}
                                            {error === UploadError.NotFound && siteMessage("Product_NotFound")}
                                            {error === UploadError.OutOfStock && translate("Out of stock")}
                                            {error === UploadError.Negative &&
                                                siteMessage("Vmi_VmiBinMinimumQuantityMustBeGreaterThanZero")}
                                            {error === UploadError.MinimumBiggerMaximum &&
                                                siteMessage("Vmi_VmiBinMinimumQtyMustBeLessThanOrEqualToMaximumQty")}
                                            {(error === UploadError.Existed || error === UploadError.Over25Chars) &&
                                                message}
                                            {error === UploadError.BinNegativeCount &&
                                                translate("Vmi_NegativeCount_BadRequest")}
                                            {error === UploadError.BinNotFound && translate("Vmi_BinNotFound")}
                                            {error === UploadError.WrongType && translate("Vmi_Count_Wrong_Type")}
                                            {error === UploadError.MisMatch && translate("Vmi_Count_Product_Mismatch")}
                                            {error === UploadError.ProductRequired &&
                                                translate("Vmi_Count_Product_Required")}
                                            {error === UploadError.CountNotProvided &&
                                                translate("Vmi_Count_Not_Provided")}
                                        </DataTableCell>
                                    </DataTableRow>
                                ))}
                            </DataTableBody>
                        </DataTable>
                    </StyledWrapper>
                )}
                {errorMessages.length > 0 && (
                    <StyledWrapper {...styles.tableWrapper}>
                        <DataTable {...styles.dataTable}>
                            <DataTableHead {...styles.tableHead}>
                                <DataTableHeader {...styles.errorLineHeader}>{translate("Error")}</DataTableHeader>
                            </DataTableHead>
                            <DataTableBody {...styles.tableBody}>
                                {errorMessages.map(message => (
                                    <DataTableRow key={message} {...styles.tableRow}>
                                        <DataTableCell {...styles.errorLineCell}>{message}</DataTableCell>
                                    </DataTableRow>
                                ))}
                            </DataTableBody>
                        </DataTable>
                    </StyledWrapper>
                )}
                <GridItem {...styles.buttonsGridItem}>
                    <Button {...styles.cancelButton} type="button" onClick={() => closeModalHandler(true)}>
                        {translate(continueImport ? "Cancel Import" : "Cancel")}
                    </Button>
                    {!continueImport && (
                        <Button
                            {...styles.importButton}
                            type="button"
                            disabled={
                                !file ||
                                isBadFile ||
                                isUploading ||
                                errorMessages.length > 0 ||
                                !vmiBins ||
                                vmiBins.length === 0
                            }
                            onClick={onImportClick}
                        >
                            {translate("Import")}
                        </Button>
                    )}
                    {continueImport && (
                        <Button
                            {...styles.importButton}
                            type="button"
                            disabled={!products || products.length === 0 || !dataToImport || dataToImport.length === 0}
                            onClick={importCounts}
                        >
                            {translate("Continue Import")}
                        </Button>
                    )}
                </GridItem>
            </GridContainer>
        </Modal>
    );
};

export default connect(mapStateToProps, mapDispatchToProps)(withToaster(VmiCountsImportModal));
