import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { PageRoute, RouterExtensions } from '@nativescript/angular';
import { Connectivity } from '@nativescript/core';
import { confirm } from '@nativescript/core/ui/dialogs';
import { Select, Store } from '@ngxs/store';
import { FeedbackType } from 'nativescript-feedback';
import { ListViewEventData } from 'nativescript-ui-listview';
import { Observable } from 'rxjs';
import { switchMap, withLatestFrom } from 'rxjs/operators';
import { StockTakingAllOutput } from '../../entities/output/stockTakingAllOutput';
import { StockTakingWarehouseItemInsertOutput } from '../../entities/output/stockTakingWarehouseItemInsertOutput';
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 {
    CreateStockTakingWarehouseItemInsert,
    LoadWarehouseItemAllStockTaking
} from '../../state-mgmt/inventory-waiting-confirm.action';
import { InventoryWaitingConfirmState } from '../../state-mgmt/inventory-waiting-confirm.state';
import { feedbackMessage } from '../../utils/feedback-messages';

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

export class InventoryWaitingConfirmComponent implements OnInit {
    @ViewChild('list', {static: true}) list: ElementRef;

    @Select(InventoryWaitingConfirmState.getWarehouseItemAllStockTaking) warehouseItemAllStockTaking$: Observable<WarehouseItemAllStockTakingOutput[]>;
    @Select(InventoryWaitingConfirmState.getStockTakingWarehouseItemInsert) stockTakingWarehouseItemInsert$: Observable<StockTakingWarehouseItemInsertOutput>;
    @Select(InventoryWaitingConfirmState.isLoading) isLoading$: Observable<boolean>;
    stockTakingWarehouseItemInsert: StockTakingWarehouseItemInsertOutput;
    warehouseItemAllStockTaking: WarehouseItemAllStockTakingOutput[];

    idWarehouse: number;
    warehouse: WarehouseAllOutput = null;
    currentInventory: StockTakingAllOutput = null;
    items: WarehouseItemAllOutput[];
    othersIsLoading: boolean;
    isAnyLocalChange: boolean = false;

    constructor(
        private router: Router,
        private routerExtensions: RouterExtensions,
        private pageRoute: PageRoute,
        private store: Store,
        private database: DatabaseService
    ) {
        this.router.events.subscribe((val) => {
            if (val instanceof NavigationEnd) {
                if (RegExp('\/material\/inventoryWaitingConfirm\/[0-9]+').test(this.router.url)) {
                    this.othersIsLoading = false;
                }
            }
        });
    }

    ngOnInit(): void {
        this.othersIsLoading = false;
        this.pageRoute.activatedRoute
            .pipe(
                switchMap(activatedRoute => activatedRoute.params)
            )
            .forEach((params) => {
                this.idWarehouse = +params['id'];
            });
        this.database.loadItems(this.idWarehouse)
                .then((items) => {
                    this.items = items.sort((item1: { DisplayName: string; }, item2: { DisplayName: string; }) => {
                        return item1.DisplayName.toLowerCase()
                            .localeCompare(item2.DisplayName.toLowerCase(), 'cs', {
                            numeric: true,
                            sensitivity: 'base'
                        });
                    });
                    this.isAnyLocalChange = this.items.find(i => i.localChange === true) !== undefined;
                    this.database.loadWarehouse(this.idWarehouse)
                        .then((warehouse) => {
                            this.warehouse = warehouse[0];
                            this.database.loadStockTaking(this.warehouse.DisplayName.trim())
                                .then((inventory) => {
                                    this.currentInventory = inventory[0];
                                    this.othersIsLoading = false;

                                }, err => {
                                    feedbackMessage(FeedbackType.Warning, 'Inventarizace', `V daném skladu neprobíhá žádná inventura.`);
                                    this.othersIsLoading = false;
                                    console.log(err);
                                });
                        }, err => {
                            feedbackMessage(FeedbackType.Error, 'Inventarizace', `Nelze najít sklad.`);
                            this.othersIsLoading = false;
                            console.log(err);
                        });
                }, err => {
                    feedbackMessage(FeedbackType.Error, 'Inventarizace', `Nelze načíst položky.`);
                    this.othersIsLoading = false;
                    console.log(err);
                });
    }

    onTapItem(event: ListViewEventData) {
        this.items[event.index].expanded = !this.items[event.index].expanded;
    }

    /**
     * removes item from waiting items - item becomes noninventorized
     * @param item item which will be removed from list of items waiting to confirm inventory
     */
    uninventorizeItem(item: WarehouseItemAllOutput) {
        if (item.localChange) {
            item.localChange = false;
            item.idLastInventory = null;
            this.database.updateItemLocal(item);
            this.database.updateItemLastInventoryId(item);
            item.expanded = false;
            this.isAnyLocalChange = this.items.find(i => i.localChange === true) !== undefined;
        } else {
            feedbackMessage(FeedbackType.Warning, 'Inventarizace', `Položka nečeká na synchronizaci.`);
        }
    }

    /**
     * submit inventory - send items to server
     * internet connection required
     */
    onSubmitInventory(): void {
        const options = {
            title: 'Inventarizace',
            message: `Opravdu chcete inventarizovat vybrané položky?

Poznámka: Je nutné připojení k internetu.`,
            okButtonText: 'Ano',
            cancelButtonText: 'Ne',
            neutralButtonText: 'Zrušit'
        };

        confirm(options).then((result: boolean) => {
            if (result) {
                const connectionType = Connectivity.getConnectionType();
                if (connectionType === Connectivity.connectionType.none) {
                    feedbackMessage(FeedbackType.Warning, 'Bez připojení k internetu', `Zkontrolujte prosím připojení k internetu.`);
                } else {
                    if (!this.currentInventory) {
                        feedbackMessage(FeedbackType.Info, 'Inventarizace', `Tato jednotka nemá založenou žádnou inventuru.`);
                    } else {
                        if (!this.warehouse) {
                            feedbackMessage(FeedbackType.Info, 'Inventarizace', `Pro tento sklad není založena žádná inventura.`);
                        } else {
                            const toInventorize: WarehouseItemAllOutput[] = this.items.filter((item) => {
                                return item.localChange === true;
                            });
                            if (toInventorize.length === 0) {
                                feedbackMessage(FeedbackType.Info, 'Inventarizace', `K inventarizaci nebyly vybrány žádné nové předměty.`);
                            } else {
                                this.submitInventorizedItems(toInventorize);
                                this.list.nativeElement.refresh();
                            }
                        }
                    }
                }
            }
        });
    }

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

    templateSelector(): string {
        return 'default';
    }

    get confirmIcon() {
        return String.fromCharCode(0xf00c);
    }

    get downIcon() {
        return String.fromCharCode(0xf107);
    }

    get rightIcon() {
        return String.fromCharCode(0xf105);
    }

    /**
     * inventorize items one after one
     * firstly, inventoriyed items are updated from server
     * then waiting items are inventorizied
     * when synchronized, localChange set to false and idLastInventory is set to current inventory
     *
     * @param {Array<WarehouseItem>} toInventorize - items to inventorize
     */
    private submitInventorizedItems(toInventorize: WarehouseItemAllOutput[]): void {
        this.store.dispatch(new LoadWarehouseItemAllStockTaking(this.currentInventory.ID, this.warehouse.ID))
        .pipe(withLatestFrom(this.warehouseItemAllStockTaking$))
        .subscribe(([_, inventorizeditems]) => {
            const uninventorized = toInventorize.filter(item => inventorizeditems.map(i => +i.ID).indexOf(+item.ID) === -1);

            if (uninventorized && uninventorized.length > 0) {
                this.store.dispatch(new CreateStockTakingWarehouseItemInsert(this.currentInventory.ID, uninventorized.map(item => item.ID)))
                .pipe(withLatestFrom(this.stockTakingWarehouseItemInsert$))
                .subscribe(([_]) => {
                    toInventorize.map(i => i.ID).forEach(i => {
                        const item = this.items.find(it => +it.ID === +i);
                        if (item) {
                            item.localChange = false;
                            item.idLastInventory = this.currentInventory.ID;
                            this.database.updateItemLocal(item);
                            this.database.updateItemLastInventoryId(item);
                        }
                    });
                    feedbackMessage(FeedbackType.Success, 'Inventarizace', `Inventarizace položek proběhla úspěšně.`);
                }, () => {
                    feedbackMessage(FeedbackType.Error, 'Inventarizace', 'Nepodařilo se přidat položky k inventarizaci.');
                });
            } else {
                feedbackMessage(FeedbackType.Info, 'Inventarizace', `K inventarizaci nebyly vybrány žádné nové předměty.`);
            }
        }, () => {
            feedbackMessage(FeedbackType.Error, 'Načtení inventarizovaných položek', 'Nepodařilo se načíst již inventarizované položky.');
        });
    }

}
