module insite.common {
    "use strict";

    import ISearchFilter = insite.catalog.ISearchFilter;

    enum LocationUploadError {
        None,
        NoBillTo,
        BillToNotFound,
        NoShipTo,
        ShipToNotFound,
        NoLocationName,
        DuplicateLocationName,
        DuplicateLocationNameSameFile,
        LocationNameTooLong
    }

    export class VmiLocationImportPopupController extends common.BaseUploadController {
        currentBillTo: BillToModel;
        totalLocationCount: number;
        errorEntries: any[] = null;
        fullFileError: boolean;
        importedItems: VmiLocationModel[];
        firstRowHeading = true;

        static $inject = [
            "$rootScope",
            "$scope",
            "productService",
            "vmiLocationsService",
            "customerService",
            "coreService",
            "settingsService",
            "vmiLocationImportPopupService",
            "sessionService"];

        constructor(
            protected $rootScope: ng.IRootScopeService,
            protected $scope: ng.IScope,
            protected productService: catalog.IProductService,
            protected vmiLocationsService: catalog.IVmiLocationsService,
            protected customerService: customers.ICustomerService,
            protected coreService: core.ICoreService,
            protected settingsService: core.ISettingsService,
            protected vmiLocationImportPopupService: IVmiLocationImportPopupService,
            protected sessionService: account.ISessionService) {
            super($scope, productService, coreService, settingsService);
            this.vmiLocationImportPopupService.registerDisplayFunction((data) => {
                this.cleanupUploadData();
                this.totalLocationCount = data.totalLocationCount;
                this.badFile = false;
                this.file = null;
                this.fileName = null;
                this.fullFileError = false;
                this.uploadLimitExceeded = false;
                this.coreService.displayModal("#VmiLocationImportPopup");
            });
        }

        protected processWb(wb): void {
            this.itemsToSearch = [];
            wb.SheetNames.forEach((sheetName) => {
                const opts = { header: 1 };
                let roa = this.XLSX.utils.sheet_to_row_object_array(wb.Sheets[sheetName], opts);
                if (roa.length > 0) {
                    if (this.firstRowHeading) {
                        roa = roa.slice(1, roa.length);
                    }
                    roa = roa.filter(r => (r[0] != null && r[0].length > 0) || (r[1] != null && r[1].length > 0) || (r[2] != null && r[2].length > 0));
                    if (this.limitExceeded(roa.length)) {
                        return;
                    }
                    roa.forEach((r) => {
                        let objectToAdd = { customerNumber: r[0], customerSequence: r[1], name: r[2], useBins: r[3] ? r[3].toString().toLowerCase() : 'false' };

                        if (objectToAdd.useBins === '1') {
                            objectToAdd.useBins = 'true';
                        } else {
                            objectToAdd.useBins = 'false';
                        }

                        this.itemsToSearch.push(objectToAdd);
                    });
                }
            });

            this.batchGetFromApi();
        }

        protected processCsv(data: string): void {
            this.itemsToSearch = [];
            const newLineIndex = data.lastIndexOf("\r\n");
            if (newLineIndex + 2 === data.length) {
                data = data.substr(0, newLineIndex);
            }
            const results = Papa.parse(data);
            if (results.errors.length > 0) {
                this.badFile = true;
                return;
            }
            let rows = results.data;
            if (this.firstRowHeading) {
                rows = rows.slice(1, rows.length);
            }
            if (this.limitExceeded(rows.length)) {
                return;
            }
            rows.forEach((s) => {
                if ((s[0] == null || s[0].length === 0) && (s[1] == null || s[1].length === 0) && (s[2] == null || s[2].length === 0)) {
                    return;
                }
                const objectToAdd: any = {};
                objectToAdd.customerNumber = s[0];
                objectToAdd.customerSequence = s[1];
                objectToAdd.name = s[2];
                if (s[3]) {
                    objectToAdd.useBins = s[3] ? s[3] : 'false';
                }

                if (objectToAdd.useBins === '1') {
                    objectToAdd.useBins = 'true';
                } else {
                    objectToAdd.useBins = 'false';
                }

                this.itemsToSearch.push(objectToAdd);
            });
            this.batchGetFromApi();
        }

        protected batchGetFromApi(): void {
            this.errorEntries = [];
            this.importedItems = [];

            if (this.itemsToSearch.length === 0) {
                this.badFile = true;
                return;
            }

            this.validateLocations();
        }

        protected validateLocations(): void {
            if (this.uploadCancelled) {
                return;
            }

            this.customerService.getBillTo("shiptos,excludeonetime,excludecreatenew,country,state").then(
                (billTo: BillToModel) => { this.getBillToCompleted(billTo); },
                (error: any) => { this.getBillToFailed(error); });
        }

        protected validateLocationsFailed(error: any): void {
            // server gave us back an error, need to let user know the file was using incorrect format
            this.fullFileError = true;
            if (this.uploadCancelled) {
                return;
            }

            this.checkCompletion();
        }

        protected getBillToCompleted(billTo: BillToModel): void {
            if (this.uploadCancelled) {
                return;
            }

            this.currentBillTo = billTo;

            const filter: ISearchFilter = {
                page: 1,
                pageSize: 9999 // get all locations
            }

            this.vmiLocationsService.getVmiLocations(filter).then(
                (locationCollection: VmiLocationCollectionModel) => {
                    this.processLocations(locationCollection.vmiLocations);
                    if (this.errorEntries.length <= 0) {
                        this.vmiLocationsService.batchAddVmiLocations(this.importedItems, false).then(
                            () => { this.addLocationsCompleted(); },
                            (error: any) => { this.addLocationsFailed(error); });
                    }
                    else {
                        this.checkCompletion();
                    }
                },
                (error: any) => { this.getLocationsFailed(error); });
        }

        protected getLocationsFailed(error: any): void {
        }

        protected getBillToFailed(error: any): void {
        }

        protected processLocations(locations?: VmiLocationModel[]) {
            for (let i = 0; i < this.itemsToSearch.length; i++) {
                const index = this.firstRowHeading ? i + 2 : i + 1;
                const error = this.validateLocationData(this.itemsToSearch[i], locations);
                if (error === LocationUploadError.None) {
                    this.importedItems.push({
                        name: this.itemsToSearch[i].name,
                        billToId: this.currentBillTo?.id,
                        shipToId: this.currentBillTo?.shipTos?.find(
                            x => x.customerSequence.toLowerCase() === this.itemsToSearch[i].customerSequence?.toLowerCase(),
                        )?.id,
                        isPrimaryLocation: this.itemsToSearch[i].isPrimaryLocation,
                        useBins: this.itemsToSearch[i].useBins,
                    } as any as VmiLocationModel);
                } else {
                    this.errorEntries.push(this.mapLocationErrorInfo(index, error, this.itemsToSearch[i].customerNumber, this.itemsToSearch[i].customerSequence, this.itemsToSearch[i].name));
                }
            };
        }

        protected validateLocationData(row: any, locations: VmiLocationModel[]): LocationUploadError {
            if (!row.customerNumber) {
                return LocationUploadError.NoBillTo;
            }
            if (row.customerNumber.toLowerCase() !== this.currentBillTo.customerNumber.toLowerCase()) {
                return LocationUploadError.BillToNotFound;
            }
            if (row.customerSequence === null) {
                return LocationUploadError.NoShipTo;
            }
            const shipTo =
                row.customerSequence === ""
                    ? this.currentBillTo
                    : this.currentBillTo.shipTos?.find(
                        x => x.customerSequence.toLowerCase() === row.customerSequence?.toLowerCase(),
                    );
            if (!shipTo) {
                return LocationUploadError.ShipToNotFound;
            }
            if (!row.name) {
                return LocationUploadError.NoLocationName;
            }
            if (row.name.length > 255) {
                return LocationUploadError.LocationNameTooLong;
            }
            const existingVmiLocation = locations?.filter(
                l =>
                    l?.name?.toLowerCase() === row.name.toLowerCase() &&
                    l?.shipToId?.toString().toLowerCase() === shipTo.id?.toLowerCase(),
            );
            if (existingVmiLocation && existingVmiLocation.length > 0) {
                return LocationUploadError.DuplicateLocationName;
            }
            if (this.importedItems.find(x => x.name.toLowerCase() === row.name.toLowerCase() && x.shipToId?.toString().toLowerCase() === shipTo.id.toLowerCase())) {
                return LocationUploadError.DuplicateLocationNameSameFile;
            }

            return LocationUploadError.None;
        }

        protected mapLocationErrorInfo(index: number, error: LocationUploadError, customerNumber: string, customerSequence: string, name: string): any {
            return {
                customerNumber,
                customerSequence,
                name,
                index: index,
                error: LocationUploadError[error],
            };
        }

        protected checkCompletion(): void {
            if (this.uploadCancelled) {
                return;
            }

            if (this.importedItems && this.errorEntries.length === 0 && !this.fullFileError) {
                this.uploadProducts();
            } else {
                this.hideUploadingPopup();
                setTimeout(() => {
                    this.showUploadingIssuesPopup();
                }, 250); // Foundation.libs.reveal.settings.animation_speed
            }
        }

        protected uploadProducts(popupSelector?: string): void {
            if (popupSelector) {
                this.coreService.closeModal(popupSelector);
            }

            this.allowCancel = false;

            this.vmiLocationsService.batchAddVmiLocations(this.importedItems, false).then(
                () => {
                    this.addLocationsCompleted();
                },
                (error: any) => { this.addLocationsFailed(error); });
        }

        protected addLocationsCompleted(): void {
            this.uploadingCompleted();
        }

        protected addLocationsFailed(error: any): void {
        }

        protected uploadingCompleted(): void {
            this.hideUploadingPopup();
            this.uploadedItemsCount = this.importedItems.length;

            setTimeout(() => {
                this.showUploadSuccessPopup();
                this.cleanupUploadData();
            }, 250);
        }

        protected cleanupUploadData(): void {
            this.file = null;
            this.fileName = null;
            this.firstRowHeading = true;
            this.errorEntries = null;
            this.fullFileError = false;
            this.importedItems = null;
        }

        protected showUploadingPopup() {
            this.coreService.displayModal(angular.element("#locationUploadingPopup"));
        }

        protected hideUploadingPopup() {
            this.coreService.closeModal("#locationUploadingPopup");
        }

        protected showUploadSuccessPopup() {
            this.coreService.displayModal(angular.element("#locationUploadSuccessPopup"), this.onCompletion());
        }

        onCompletion(): void {
            this.cleanupUploadData();

            this.$rootScope.$broadcast("UploadingItemsCompleted");
        }

        protected hideUploadSuccessPopup() {
            this.coreService.closeModal("#locationUploadSuccessPopup");
        }

        protected showUploadingIssuesPopup() {
            this.coreService.displayModal(angular.element("#locationUploadingIssuesPopup"));
        }

        protected hideUploadingIssuesPopup() {
            this.coreService.closeModal("#locationUploadingIssuesPopup");
        }
    }

    export interface IVmiLocationImportPopupService {
        display(data: any): void;
        registerDisplayFunction(p: (data: any) => void);
    }

    export class VmiLocationImportPopupService extends base.BasePopupService<any> implements IVmiLocationImportPopupService {
        protected getDirectiveHtml(): string {
            return "<isc-vmi-location-import-popup></isc-vmi-location-import-popup>";
        }
    }

    angular
        .module("insite")
        .controller("VmiLocationImportPopupController", VmiLocationImportPopupController)
        .service("vmiLocationImportPopupService", VmiLocationImportPopupService)
        .directive("iscVmiLocationImportPopup", () => ({
            restrict: "E",
            replace: true,
            templateUrl: "/PartialViews/Catalog-VmiLocationImportPopup",
            controller: "VmiLocationImportPopupController",
            controllerAs: "vm",
            bindToController: true
        }));
}