import { ApplicationSettings, ImageSource } from '@nativescript/core';
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { APP_ID, wsDocumentStorage, 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 { WarehouseItemReservationAll } from '../entities/input/warehouseItemReservationAll';
import { WarehouseItemDetailOutput } from '../entities/output/warehouseItemDetailOutput';
import { WarehouseItemReservationAllOutput } from '../entities/output/warehouseItemReservationAllOutput';
import { LoadItemDetail, LoadPhotoContent, LoadWarehouseItemReservationAll } from './material-detail.action';

import { DocumentDetailData } from '../entities/input/documentDetailData';
import { DocumentDetailDataOutput } from '../entities/output/documentDetailDataOutput';

export interface MaterialDetailStateModel {
    loadingWarehouseItemReservationAll: boolean;
    loadingItemDetail: boolean;
    loadingPhotoContent: boolean;
    warehouseItemReservationAll: WarehouseItemReservationAllOutput[];
    itemDetail: WarehouseItemDetailOutput;
    photoContent: ImageSource;
}

const initialStateModel: MaterialDetailStateModel = {
    loadingWarehouseItemReservationAll: false,
    loadingItemDetail: false,
    loadingPhotoContent: false,
    warehouseItemReservationAll: [],
    itemDetail: null,
    photoContent: null
};

@State<MaterialDetailStateModel>({
    name: 'materialDetail',
    defaults: initialStateModel
})
export class MaterialDetailState {
    @Selector()
    static getwarehouseItemReservationAll(state: MaterialDetailStateModel) {
        return state.warehouseItemReservationAll;
    }

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

    @Selector()
    static getImageSource(state: MaterialDetailStateModel) {
        return state.photoContent;
    }

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

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load reservations
     *
     * @param {StateContext<MaterialDetailStateModel>} ctx
     * @param {LoadWarehouseItemReservationAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadWarehouseItemReservationAll)
    loadWarehouseItemReservationAll(ctx: StateContext<MaterialDetailStateModel>, 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;
            })
        );
    }

    /**
     * Load item detail
     *
     * @param {StateContext<MaterialDetailStateModel>} ctx
     * @param {LoadItemDetail} action
     * @returns {Observable<any>}
     */
    @Action(LoadItemDetail)
    loadItemDetail(ctx: StateContext<MaterialDetailStateModel>, 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 položky.');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingItemDetail: false,
                        itemDetail: initialStateModel.itemDetail
                    });

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

    /**
     * Load item photo
     *
     * @param {StateContext<MaterialDetailStateModel>} ctx
     * @param {LoadPhotoContent} action
     * @returns {Observable<any>}
     */
    @Action(LoadPhotoContent)
    loadPhotoContent(ctx: StateContext<MaterialDetailStateModel>, action: LoadPhotoContent) {
        ctx.patchState({
            loadingPhotoContent: true
        });

        if (action.id) {
            return this.webApiService.call(
                new DocumentDetailData(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.id),
                () => new DocumentDetailDataOutput(),
                wsDocumentStorage
            ).pipe(
                tap((response: string) => {
                    if (response !== null) {
                        ctx.patchState({
                            loadingPhotoContent: false,
                            photoContent: ImageSource.fromBase64Sync(response)
                        });
                    } else {
                        ctx.patchState({
                            loadingPhotoContent: false,
                            photoContent: initialStateModel.photoContent
                        });
                        throw new Error('Nepodařilo se nalézt detail položky.');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingPhotoContent: false,
                        photoContent: initialStateModel.photoContent
                    });

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

}
