import { ApplicationSettings } from '@nativescript/core';
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { APP_ID, wsMaterial } from '~/constants/api.constants';
import { USER_TOKEN, USER_UNIT_ID } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { PurchaseTypeAll } from '../entities/input/purchaseTypeAll';
import { WarehouseAll } from '../entities/input/warehouseAll';
import { WarehouseItemCategoryAll } from '../entities/input/warehouseItemCategoryAll';
import { WarehouseItemDetail } from '../entities/input/warehouseItemDetail';
import { WarehouseItemUpdate } from '../entities/input/warehouseItemUpdate';
import { PurchaseTypeAllOutput } from '../entities/output/purchaseTypeAllOutput';
import { WarehouseAllOutput } from '../entities/output/warehouseAllOutput';
import { WarehouseItemCategoryAllOutput } from '../entities/output/warehouseItemCategoryAllOutput';
import { WarehouseItemDetailOutput } from '../entities/output/warehouseItemDetailOutput';
import { WarehouseItemUpdateOutput } from '../entities/output/warehouseItemUpdateOutput';
import {
    CreateItemUpdate,
    LoadItemDetail,
    LoadPurchaseTypeAll,
    LoadWarehouseAll,
    LoadWarehouseItemCategoryAll
} from './material-update.action';

export interface MaterialUpdateStateModel {
    loadingWarehouseItemDetail: boolean;
    loadingWarehouses: boolean;
    loadingCategories: boolean;
    loadingPurchaseTypes: boolean;
    loadingItemUpdate: boolean;
    warehouseItemDetail: WarehouseItemDetailOutput;
    warehouses: WarehouseAllOutput[];
    itemCategories: WarehouseItemCategoryAllOutput[];
    purchaseTypes: PurchaseTypeAllOutput[];
    itemUpdate: WarehouseItemUpdateOutput;
}

const initialStateModel: MaterialUpdateStateModel = {
    loadingWarehouseItemDetail: false,
    loadingWarehouses: false,
    loadingCategories: false,
    loadingPurchaseTypes: false,
    loadingItemUpdate: false,
    warehouseItemDetail: null,
    warehouses: [],
    itemCategories: [],
    purchaseTypes: [],
    itemUpdate: null

};

@State<MaterialUpdateStateModel>({
    name: 'materialUpdate',
    defaults: initialStateModel
})
export class MaterialUpdateState {
    @Selector()
    static getWarehouseItemDetail(state: MaterialUpdateStateModel) {
        return state.warehouseItemDetail;
    }

    @Selector()
    static getWarehouses(state: MaterialUpdateStateModel) {
        return state.warehouses;
    }

    @Selector()
    static getItemCategories(state: MaterialUpdateStateModel) {
        return state.itemCategories;
    }

    @Selector()
    static getPurchaseTypes(state: MaterialUpdateStateModel) {
        return state.purchaseTypes;
    }

    @Selector()
    static getItemUpdate(state: MaterialUpdateStateModel) {
        return state.itemUpdate;
    }

    @Selector()
    static isLoading(state: MaterialUpdateStateModel) {
        return state.loadingWarehouseItemDetail
            || state.loadingWarehouses
            || state.loadingCategories
            || state.loadingPurchaseTypes
            || state.loadingItemUpdate;
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load item detail
     *
     * @param {StateContext<MaterialUpdateStateModel>} ctx
     * @param {LoadItemDetail} action
     * @returns {Observable<any>}
     */
    @Action(LoadItemDetail)
    loadWarehouseItemDetail(ctx: StateContext<MaterialUpdateStateModel>, action: LoadItemDetail) {
        ctx.patchState({
            loadingWarehouseItemDetail: true
        });

        if (action.id) {
            return this.webApiService.call(
                new WarehouseItemDetail(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.id),
                () => new WarehouseItemDetailOutput(),
                wsMaterial
            ).pipe(
                tap((response: WarehouseItemDetailOutput[]) => {
                    if (response.length === 1) {
                        ctx.patchState({
                            loadingWarehouseItemDetail: false,
                            warehouseItemDetail: response[0]
                        });
                    } else {
                        ctx.patchState({
                            loadingWarehouseItemDetail: false,
                            warehouseItemDetail: initialStateModel.warehouseItemDetail
                        });
                        throw new Error('Nepodařilo se nalézt detail polozky');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingWarehouseItemDetail: false,
                        warehouseItemDetail: initialStateModel.warehouseItemDetail
                    });

                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingWarehouseItemDetail: false
            });
        }
    }

    /**
     * Load warehouses
     *
     * @param {StateContext<MaterialUpdateStateModel>} ctx
     * @param {LoadWarehouseAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseAll)
    loadWarehouseAll(ctx: StateContext<MaterialUpdateStateModel>, action: LoadWarehouseAll) {
        ctx.patchState({
            loadingWarehouses: true
        });

        return this.webApiService.call(
            new WarehouseAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_UNIT_ID)),
            () => new WarehouseAllOutput(),
            wsMaterial
        ).pipe(
            tap((response: WarehouseAllOutput[]) => {
                ctx.patchState({
                    loadingWarehouses: false,
                    warehouses: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingWarehouses: false,
                    warehouses: initialStateModel.warehouses
                });

                throw e;
            })
        );
    }

    /**
     * Load item categories
     *
     * @param {StateContext<MaterialUpdateStateModel>} ctx
     * @param {LoadWarehouseItemCategoryAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseItemCategoryAll)
    loadWarehouseItemCategoryAll(ctx: StateContext<MaterialUpdateStateModel>, action: LoadWarehouseItemCategoryAll) {
        ctx.patchState({
            loadingCategories: true
        });

        return this.webApiService.call(
            new WarehouseItemCategoryAll(APP_ID, ApplicationSettings.getString(USER_TOKEN)),
            () => new WarehouseItemCategoryAllOutput(),
            wsMaterial
        ).pipe(
            tap((response: WarehouseItemCategoryAllOutput[]) => {
                ctx.patchState({
                    loadingCategories: false,
                    itemCategories: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingCategories: false,
                    itemCategories: initialStateModel.itemCategories
                });

                throw e;
            })
        );
    }

    /**
     * Load item purchase types
     *
     * @param {StateContext<MaterialUpdateStateModel>} ctx
     * @param {LoadPurchaseTypeAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadPurchaseTypeAll)
    loadPurchaseTypeAll(ctx: StateContext<MaterialUpdateStateModel>, action: LoadPurchaseTypeAll) {
        ctx.patchState({
            loadingPurchaseTypes: true
        });

        return this.webApiService.call(
            new PurchaseTypeAll(APP_ID, ApplicationSettings.getString(USER_TOKEN)),
            () => new PurchaseTypeAllOutput(),
            wsMaterial
        ).pipe(
            tap((response: PurchaseTypeAllOutput[]) => {
                ctx.patchState({
                    loadingPurchaseTypes: false,
                    purchaseTypes: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingPurchaseTypes: false,
                    purchaseTypes: initialStateModel.purchaseTypes
                });

                throw e;
            })
        );
    }

    /**
     * create item update
     *
     * @param {StateContext<MaterialUpdateStateModel>} ctx
     * @param {CreateItemUpdate} action
     * @returns {Observable<any>}
     */
    @Action(CreateItemUpdate)
    createItemUpdate(ctx: StateContext<MaterialUpdateStateModel>, action: CreateItemUpdate) {
        ctx.patchState({
            loadingItemUpdate: true
        });

        if (action.id) {
            return this.webApiService.call(
                new WarehouseItemUpdate(APP_ID, ApplicationSettings.getString(USER_TOKEN),
                    action.id, action.displayName, action.idWarehouse, action.idCategory,
                    action.invNumber, action.description, action.purchDate, action.purchaseType,
                    action.purchaseNote, action.serNumber, action.accountNumber, action.purchasePrice, action.actualPrice,
                    action.eventRent, action.unitRent, action.commercialRent, action.rentPrice, action.rentNote,
                    action.note),
                () => new WarehouseItemUpdateOutput(),
                wsMaterial
            ).pipe(
                tap((response: WarehouseItemUpdateOutput[]) => {
                    ctx.patchState({
                        loadingItemUpdate: false,
                        itemUpdate: response[0]
                    });
                }),
                catchError(e => {
                    console.log(e);
                    ctx.patchState({
                        loadingItemUpdate: false,
                        itemUpdate: initialStateModel.itemUpdate
                    });

                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingItemUpdate: false,
                itemUpdate: initialStateModel.itemUpdate
            });
        }
    }

}
