import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { ModalDialogOptions, ModalDialogService, RouterExtensions } from '@nativescript/angular';
import { Select, Store } from '@ngxs/store';
import { FeedbackType } from 'nativescript-feedback';
import { Observable } from 'rxjs';
import { withLatestFrom } from 'rxjs/operators';
import { transitionOptions } from '~/constants/shared.constants';
import { ModalHelpComponent } from '../../components/modal-view-help/modal-view-help.component';
import { StockTakingAllOutput } from '../../entities/output/stockTakingAllOutput';
import { WarehouseAllOutput } from '../../entities/output/warehouseAllOutput';
import { WarehouseItemAllOutput } from '../../entities/output/warehouseItemAllOutput';
import { WarehouseItemAllStockTakingOutput } from '../../entities/output/warehouseItemAllStockTakingOutput';
import { DatabaseService } from '../../services/database.service';
import {
    LoadStockTakingAll,
    LoadWarehouseAll,
    LoadWarehouseItemAll,
    LoadWarehouseItemAllStockTaking
} from '../../state-mgmt/inventory.action';
import { InventoryState } from '../../state-mgmt/inventory.state';
import { feedbackMessage } from '../../utils/feedback-messages';

@Component({
    selector: 'Inventory',
    moduleId: module.id,
    templateUrl: './inventory.component.html',
    styleUrls: ['./inventory.component.scss']
})

export class InventoryComponent implements OnInit {
    @Select(InventoryState.getWarehouses) warehouses$: Observable<WarehouseAllOutput[]>;
    @Select(InventoryState.getStockTakingAll) stockTakingAll$: Observable<StockTakingAllOutput[]>;
    @Select(InventoryState.getWarehouseItems) items$: Observable<WarehouseItemAllOutput[]>;
    @Select(InventoryState.getWarehouseItemAllStockTaking) warehouseItemAllStockTaking$: Observable<WarehouseItemAllStockTakingOutput[]>;
    @Select(InventoryState.isLoading) isLoading$: Observable<boolean>;
    warehouses: WarehouseAllOutput[];
    stockTakingAll: StockTakingAllOutput[];
    items: WarehouseItemAllOutput[];

    currentStockTaking: StockTakingAllOutput;
    currentWarehouse: WarehouseAllOutput;
    warehouseItems: WarehouseItemAllOutput[];
    isNewInventory: boolean = false;
    othersIsLoading: boolean;

    constructor(
        private router: Router,
        private routerExtensions: RouterExtensions,
        private store: Store,
        private database: DatabaseService,
        private modalService: ModalDialogService,
        private viewContainerRef: ViewContainerRef
    ) {
        this.othersIsLoading = false;
        this.router.events.subscribe((val) => {
            if (val instanceof NavigationEnd) {
                if (this.router.url === '/inventory') {
                    this.othersIsLoading = false;
                }
            }
        });
    }

    onLoad() {
        this.othersIsLoading = false;
        this.store.dispatch(new LoadWarehouseAll())
            .pipe(withLatestFrom(this.warehouses$))
            .subscribe(([_, warehouses]) => {
                this.warehouses = warehouses;
            }, err => {
                feedbackMessage(FeedbackType.Error, 'Načtení skladů', 'Nepodařilo se načíst sklady.');
                console.log(err);
            });
        this.store.dispatch(new LoadStockTakingAll())
            .pipe(withLatestFrom(this.stockTakingAll$))
            .subscribe(([_, stockTaking]) => {
                this.stockTakingAll = stockTaking;

                this.isNewInventory = this.stockTakingAll.filter(inventory => inventory.ID_StockTakingState === 'new').length !== 0;

            }, err => {
                feedbackMessage(FeedbackType.Error, 'Načtení inventarizací', 'Nepodařilo se načíst inventarizace.');
                console.log(err);
            });
    }

    ngOnInit(): void {
        this.othersIsLoading = false;

    }

    onBackButton(): void {
        this.routerExtensions.back();
    }

    onNewInventoryTap() {
        this.othersIsLoading = true;
        let lastInventoryClosed = '';   // necessary for min date of inventories (mustn't be older than last one)
        if (this.stockTakingAll.length > 0) {
            const sortedFirstClosed = this.stockTakingAll.sort((inventory1, inventory2) =>  inventory2.ID - inventory1.ID)
                .find(inventory => inventory.ID_StockTakingState === 'closed');
            lastInventoryClosed = sortedFirstClosed ? sortedFirstClosed.Date : '';
        }
        setTimeout(() => {
            this.routerExtensions.navigate(['material/inventoryNew', lastInventoryClosed], {transition: transitionOptions});
        }, 10);
    }

    onTapWarehouse(warehouse: WarehouseAllOutput) {
        // this.database.deleteTables();    // for debugging
        // return;

        this.othersIsLoading = true;
        if (this.stockTakingAll && this.stockTakingAll.length >= 1) {
            this.currentWarehouse = this.warehouses.find(w => +w.ID === +warehouse.ID);
            const stockTakings =  this.stockTakingAll.filter(s => s.Warehouses.includes(this.currentWarehouse.DisplayName));
            this.currentStockTaking = stockTakings.length > 0 ? stockTakings.find(st => st.ID_StockTakingState === 'new') : null;
            if (!this.currentStockTaking) {
                feedbackMessage(FeedbackType.Info, 'Inventura', `V daném skladě neprobíhá žádná inventura.`);
            } else {
                this.stockTakingAll.forEach(st => {
                    this.database.insertInventory(st);  // updating old inventories (mainly because of states)
                });
                this.database.insertWarehouse(this.currentWarehouse);
                this.store.dispatch(new LoadWarehouseItemAll())
                    .pipe(withLatestFrom(this.items$))
                    .subscribe(([_, items]) => {
                        const filteredItems = items.filter(i => +i.ID_Warehouse === +warehouse.ID);
                        filteredItems.forEach(item => {
                            this.database.insertItem(item);
                        });
                        this.store.dispatch(new LoadWarehouseItemAllStockTaking(this.currentStockTaking.ID, this.currentWarehouse.ID))
                            .pipe(withLatestFrom(this.warehouseItemAllStockTaking$))
                            .subscribe(([_, inventorizeditems]) => {
                                inventorizeditems.forEach(inventorizedItem => {
                                    const matchingItem = items.find(item => {   // inventorized items
                                        return item.ID === inventorizedItem.ID;
                                    });
                                    if (matchingItem) {
                                        matchingItem.localChange = false;
                                        matchingItem.idLastInventory = this.currentStockTaking.ID;
                                        this.database.updateItemLocal(matchingItem);
                                        this.database.updateItemLastInventoryId(matchingItem);
                                    }
                                });
                                this.othersIsLoading = false;
                                setTimeout(() => {
                                    this.routerExtensions.navigate(['material/inventoryWarehouse', this.currentWarehouse.ID, this.currentWarehouse.DisplayName], {transition: transitionOptions});
                                }, 20);

                            }, err => {
                                this.othersIsLoading = false;
                                console.log(err);
                                feedbackMessage(FeedbackType.Error, 'Inventura', `Při načítání inventarizovaných položek ze serveru nastala chyba. Zkuste to prosím později. `);
                            });
                    }, err => {
                        this.othersIsLoading = false;
                        console.log(err);
                        feedbackMessage(FeedbackType.Error, 'Inventura', `Při načítání položek ze serveru nastala chyba. Zkuste to prosím později.`);
                    });
            }
        } else {
            this.othersIsLoading = false;
            feedbackMessage(FeedbackType.Info, 'Inventura', `V dané jednotce neprobíhá žádná inventura.`);
        }
    }

    /**
     * shows modal view with help about inventorizing
     */
    showModalHelp() {
        this.othersIsLoading = true;
        const options: ModalDialogOptions = {
            viewContainerRef: this.viewContainerRef,
            context: {
                label: 'Inventarizace',
                messages: ['Inventarizaci je možné provádět offline, je pouze potřeba vybrat sklad, ve kterém bude inventura prováděna. Položky se načtou do lokální databáze, proto je možné aplikaci minimalizovat a znovu maximalizovat až ve skladu (i bez připojení k internetu). Pokud však aplikaci zavřete, nebudete se bez přístupu k internetu moct přihlásit a tudíž ani provádět inventarizaci.',
                    'Při procházení skladu přidejte položky k inventarizování (naskenováním kódu nebo pomocí symbolu fajfky).',
                    'Při odchodu je potvrďte k inventarizaci. Tento postup je možné provést několikrát, není nutné inventarizovat najednou všechny položky.',
                    'Až budou všechny chtěné položky inventarizovány, je potřeba inventuru uzavřít (zrušit) přes webové rozhraní.'
                        ]
            },
            fullscreen: false
        };
        this.othersIsLoading = false;
        this.modalService.showModal(ModalHelpComponent, options);
    }

    get newIcon() {
        return String.fromCharCode(0xf271);
    }

    get helpIcon() {
        return String.fromCharCode(0xf059);
    }
}
