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 } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { WarehouseItemDetail } from '../entities/input/warehouseItemDetail';
import { WarehouseItemRentInsert } from '../entities/input/warehouseItemRentInsert';
import { WarehouseItemReservationAll } from '../entities/input/warehouseItemReservationAll';
import { WarehouseItemDetailOutput } from '../entities/output/warehouseItemDetailOutput';
import { WarehouseItemRentInsertOutput } from '../entities/output/warehouseItemRentInsertOutput';
import { WarehouseItemReservationAllOutput } from '../entities/output/warehouseItemReservationAllOutput';
import { CreateWarehouseItemRentInsert, LoadItemDetail, LoadWarehouseItemReservationAll } from './material-lend.action';

export interface MaterialLendStateModel {
    loadingWarehouseItemRentInsert: boolean;
    loadingWarehouseItemReservationAll: boolean;
    loadingItemDetail: boolean;
    warehouseItemReservationAll: WarehouseItemReservationAllOutput[];
    itemDetail: WarehouseItemDetailOutput;
 }

const initialStateModel: MaterialLendStateModel = {
    loadingWarehouseItemRentInsert: false,
    loadingWarehouseItemReservationAll: false,
    loadingItemDetail: false,
    warehouseItemReservationAll: [],
    itemDetail: null

};

@State<MaterialLendStateModel>({
     name: 'materialLend',
     defaults: initialStateModel
 })
 export class MaterialLendState {
    @Selector()
    static getWarehouseItemReservationAll(state: MaterialLendStateModel) {
        return state.warehouseItemReservationAll;
    }

    @Selector()
    static getItemDetail(state: MaterialLendStateModel) {
        return state.itemDetail;
    }

    @Selector()
     static isLoading(state: MaterialLendStateModel) {
         return state.loadingWarehouseItemReservationAll || state.loadingWarehouseItemRentInsert || state.loadingItemDetail;
     }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load reservations
     *
     * @param {StateContext<MaterialLendStateModel>} ctx
     * @param {LoadWarehouseItemReservationAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseItemReservationAll)
    loadWarehouseItemReservationAll(ctx: StateContext<MaterialLendStateModel>, action: LoadWarehouseItemReservationAll) {
        ctx.patchState({
            loadingWarehouseItemReservationAll: true
        });

        return this.webApiService.call(
            new WarehouseItemReservationAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.idItem, action.futureOnly),
            () => new WarehouseItemReservationAllOutput(),
            wsMaterial
        ).pipe(
            tap((response: WarehouseItemReservationAllOutput[]) => {
                ctx.patchState({
                    loadingWarehouseItemReservationAll: false,
                    warehouseItemReservationAll: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingWarehouseItemReservationAll: false,
                    warehouseItemReservationAll: initialStateModel.warehouseItemReservationAll
                });

                throw e;
            })
        );
    }

    /**
     * It create request for rent insert
     *
     * @param {StateContext<MaterialLendState>} ctx
     * @param {CreateWarehouseItemRentInsert} action
     * @returns {Observable<any>}
     */
    @Action(CreateWarehouseItemRentInsert)
    createWarehouseItemRentInsert(ctx: StateContext<MaterialLendStateModel>, action: CreateWarehouseItemRentInsert) {
        ctx.patchState({
            loadingWarehouseItemRentInsert: true
        });

        if (action.idItem && action.idReservation) {
            return this.webApiService.call(
                new WarehouseItemRentInsert(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.idItem, action.idReservation, action.startDate, action.note),
                () => new WarehouseItemRentInsertOutput(),
                wsMaterial
            ).pipe(
                tap((response: WarehouseItemRentInsertOutput) => {
                    ctx.patchState({
                        loadingWarehouseItemRentInsert: false
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingWarehouseItemRentInsert: false
                    });
                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingWarehouseItemRentInsert: false
            });
        }
    }

    /**
     * Load item detail
     *
     * @param {StateContext<MaterialLendStateModel>} ctx
     * @param {LoadItemDetail} action
     * @returns {Observable<any>}
     */
    @Action(LoadItemDetail)
    loadItemDetail(ctx: StateContext<MaterialLendStateModel>, action: LoadItemDetail) {
        ctx.patchState({
            loadingItemDetail: 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({
                            loadingItemDetail: false,
                            itemDetail: response[0]
                        });
                    } else {
                        ctx.patchState({
                            loadingItemDetail: false,
                            itemDetail: initialStateModel.itemDetail
                        });
                        throw new Error('Nepodařilo se nalézt detail polozky');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingItemDetail: false,
                        itemDetail: initialStateModel.itemDetail
                    });

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