import { ApplicationSettings } from '@nativescript/core';
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { APP_ID, wsOrganizationUnit } from '~/constants/api.constants';
import { USER_TOKEN, USER_UNIT_ID } from '~/constants/login-constants';
import { BaseOutput } from '~/core/entities/output/baseOutput';
import { WebApiService } from '~/core/services/web-api.service';
import { AdvertisingCategoryAll } from '../entities/input/advertisingCategoryAll';
import { AdvertisingDetail } from '../entities/input/advertisingDetail';
import { AdvertisingUpdate } from '../entities/input/advertisingUpdate';
import { MeetingDateAll } from '../entities/input/meetingDateAll';
import { AdvertisingCategoryAllResult } from '../entities/output/advertisingCategoryAllResult';
import { AdvertisingDetailResult } from '../entities/output/advertisingDetailResult';
import { MeetingDateAllResult } from '../entities/output/meetingDateAllResult';
import {
    LoadAdvertisingCategoryAll,
    LoadAdvertisingDetail,
    LoadMeetingDateAll,
    UpdateAdvertisingDetail
} from './advertising.actions';

export interface AdvertisingStateModel {
    loadingAdvertisingDetail: boolean;
    loadingAdvertisingDetailUpdate: boolean;
    loadingMeetingDateAll: boolean;
    loadingAdvertisingCategoryAll: boolean;
    advertisingDetail: AdvertisingDetailResult;
    meetingDateAll: MeetingDateAllResult[];
    advertisingCategoryAll: AdvertisingCategoryAllResult[];
}

const initialStateModel: AdvertisingStateModel = {
    loadingAdvertisingDetail: false,
    loadingAdvertisingDetailUpdate: false,
    loadingMeetingDateAll: false,
    loadingAdvertisingCategoryAll: false,
    advertisingDetail: new AdvertisingDetailResult(),
    meetingDateAll: [],
    advertisingCategoryAll: []
};

@State<AdvertisingStateModel>({
    name: 'advertising',
    defaults: initialStateModel
})
export class AdvertisingState {
    @Selector()
    static getAdvertisingDetail(state: AdvertisingStateModel) {
        return state.advertisingDetail;
    }

    @Selector()
    static getMeetingDateAll(state: AdvertisingStateModel) {
        return state.meetingDateAll;
    }

    @Selector()
    static getAdvertisingCategoryAll(state: AdvertisingStateModel) {
        return state.advertisingCategoryAll;
    }

    @Selector()
    static isLoading(state: AdvertisingStateModel) {
        return state.loadingAdvertisingDetail || state.loadingAdvertisingDetailUpdate || state.loadingMeetingDateAll || state.loadingAdvertisingCategoryAll;
    }

    constructor(
        private webApiService: WebApiService) {
    }

    /**
     * Load advertising detail
     *
     * @param {StateContext<AdvertisingStateModel>} ctx
     * @param {LoadAdvertisingDetail} action
     * @returns {Observable<any>}
     */
    @Action(LoadAdvertisingDetail)
    loadAdvertisingDetail(ctx: StateContext<AdvertisingStateModel>, action: LoadAdvertisingDetail) {
        ctx.patchState({
            loadingAdvertisingDetail: true
        });

        return this.webApiService.call(
            new AdvertisingDetail(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_UNIT_ID)),
            () => new AdvertisingDetailResult(),
            wsOrganizationUnit
        ).pipe(
            tap((response: AdvertisingDetailResult[]) => {
                ctx.patchState({
                    loadingAdvertisingDetail: false,
                    advertisingDetail: response[0]
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingAdvertisingDetail: false,
                    advertisingDetail: initialStateModel.advertisingDetail
                });

                throw e;
            })
        );
    }

    /**
     * Update advertising detail
     *
     * @param {StateContext<AdvertisingStateModel>} ctx
     * @param {UpdateAdvertisingDetail} action
     * @returns {Observable<any>}
     */
    @Action(UpdateAdvertisingDetail)
    updateAdvertisingDetail(ctx: StateContext<AdvertisingStateModel>, action: UpdateAdvertisingDetail) {
        ctx.patchState({
            loadingAdvertisingDetailUpdate: true
        });

        return this.webApiService.call(
            new AdvertisingUpdate(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_UNIT_ID), action.note),
            () => new BaseOutput(),
            wsOrganizationUnit
        ).pipe(
            tap((response) => {
                ctx.patchState({
                    loadingAdvertisingDetailUpdate: false
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingAdvertisingDetailUpdate: false
                });

                throw e;
            })
        );
    }

    /**
     * Load all meeting dates
     *
     * @param {StateContext<AdvertisingStateModel>} ctx
     * @param {LoadMeetingDateAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadMeetingDateAll)
    loadMeetingDateAll(ctx: StateContext<AdvertisingStateModel>, action: LoadMeetingDateAll) {
        ctx.patchState({
            loadingMeetingDateAll: true
        });

        return this.webApiService.call(
            new MeetingDateAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_UNIT_ID)),
            () => new MeetingDateAllResult(),
            wsOrganizationUnit
        ).pipe(
            tap((response: MeetingDateAllResult[]) => {
                ctx.patchState({
                    loadingMeetingDateAll: false,
                    meetingDateAll: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingMeetingDateAll: false,
                    meetingDateAll: initialStateModel.meetingDateAll
                });

                throw e;
            })
        );
    }

    /**
     * Load all advertising categories
     *
     * @param {StateContext<AdvertisingStateModel>} ctx
     * @param {LoadAdvertisingCategoryAll} action
     * @returns {Observable<any>}
     */
    @Action(LoadAdvertisingCategoryAll)
    loadAdvertisingCategoryAll(ctx: StateContext<AdvertisingStateModel>, action: AdvertisingCategoryAll) {
        ctx.patchState({
            loadingAdvertisingCategoryAll: true
        });

        return this.webApiService.call(
            new AdvertisingCategoryAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_UNIT_ID)),
            () => new AdvertisingCategoryAllResult(),
            wsOrganizationUnit
        ).pipe(
            tap((response: AdvertisingCategoryAllResult[]) => {
                ctx.patchState({
                    loadingAdvertisingCategoryAll: false,
                    advertisingCategoryAll: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingAdvertisingCategoryAll: false,
                    advertisingCategoryAll: initialStateModel.advertisingCategoryAll
                });

                throw e;
            })
        );
    }
}
