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 { StockTakingAll } from '../entities/input/stockTakingAll';
import { WarehouseAll } from '../entities/input/warehouseAll';
import { WarehouseItemAll } from '../entities/input/warehouseItemAll';
import { WarehouseItemAllStockTaking } from '../entities/input/warehouseItemAllStockTaking';
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 {
    LoadStockTakingAll,
    LoadWarehouseAll,
    LoadWarehouseItemAll,
    LoadWarehouseItemAllStockTaking
} from './inventory.action';

export interface InventoryStateModel {
    loadingWarehouseAll: boolean;
    loadingStockTakingAll: boolean;
    loadingWarehouseItemAll: boolean;
    loadingWarehouseItemAllStockTaking: boolean;
    warehouses: WarehouseAllOutput[];
    stockTakingAll: StockTakingAllOutput[];
    warehouseItems: WarehouseItemAllOutput[];
    warehouseItemAllStockTaking: WarehouseItemAllStockTakingOutput[];
}

const initialStateModel: InventoryStateModel = {
    loadingWarehouseAll: false,
    loadingStockTakingAll: false,
    loadingWarehouseItemAll: false,
    loadingWarehouseItemAllStockTaking: false,
    warehouses: [],
    stockTakingAll: [],
    warehouseItems: [],
    warehouseItemAllStockTaking: []
};

@State<InventoryStateModel>({
    name: 'stockTaking',
    defaults: initialStateModel
})
export class InventoryState {
    @Selector()
    static getWarehouses(state: InventoryStateModel) {
        return state.warehouses;
    }

    @Selector()
    static getStockTakingAll(state: InventoryStateModel) {
        return state.stockTakingAll;
    }

    @Selector()
    static getWarehouseItems(state: InventoryStateModel) {
        return state.warehouseItems;
    }

    @Selector()
    static getWarehouseItemAllStockTaking(state: InventoryStateModel) {
        return state.warehouseItemAllStockTaking;
    }

    @Selector()
    static isLoading(state: InventoryStateModel) {
        return state.loadingWarehouseAll || state.loadingStockTakingAll ||
        state.loadingWarehouseItemAll || state.loadingWarehouseItemAllStockTaking;
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load warehouses
     *
     * @param {StateContext<InventoryStateModel>} ctx
     * @param {LoadWarehouseAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseAll)
    loadWarehouseAll(ctx: StateContext<InventoryStateModel>, action: LoadWarehouseAll) {
        ctx.patchState({
            loadingWarehouseAll: 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({
                    loadingWarehouseAll: false,
                    warehouses: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingWarehouseAll: false,
                    warehouses: initialStateModel.warehouses
                });

                throw e;
            })
        );
    }

    /**
     * Load all stock taking
     *
     * @param {StateContext<InventoryStateModel>} ctx
     * @param {LoadStockTakingAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadStockTakingAll)
    loadStockTakingAll(ctx: StateContext<InventoryStateModel>, action: LoadStockTakingAll) {
        ctx.patchState({
            loadingStockTakingAll: true
        });

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

                throw e;
            })
        );

    }

    /**
     * Load warehouses items
     *
     * @param {StateContext<InventoryStateModel>} ctx
     * @param {LoadWarehouseItemAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseItemAll)
    loadWarehouseItemAll(ctx: StateContext<InventoryStateModel>, action: LoadWarehouseItemAll) {
        ctx.patchState({
            loadingWarehouseItemAll: true
        });

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

                throw e;
            })
        );
    }

    /**
     * Load all stock taking items
     *
     * @param {StateContext<InventoryStateModel>} ctx
     * @param {LoadWarehouseItemAllStockTaking} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseItemAllStockTaking)
    loadWarehouseItemAllStockTaking(ctx: StateContext<InventoryStateModel>, action: LoadWarehouseItemAllStockTaking) {
        ctx.patchState({
            loadingWarehouseItemAllStockTaking: true
        });

        return this.webApiService.call(
            new WarehouseItemAllStockTaking(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.idStockTaking, action.idWarehouse),
            () => new WarehouseItemAllStockTakingOutput(),
            wsMaterial
        ).pipe(
            tap((response: WarehouseItemAllStockTakingOutput[]) => {
                ctx.patchState({
                    loadingWarehouseItemAllStockTaking: false,
                    warehouseItemAllStockTaking: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingWarehouseItemAllStockTaking: false,
                    warehouseItemAllStockTaking: initialStateModel.warehouseItemAllStockTaking
                });

                throw e;
            })
        );

    }
}
