import { ApplicationSettings } from '@nativescript/core';
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { APP_ID, wsTelephony } from '~/constants/api.constants';
import { USER_PERSON_ID, USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { EnrollNumberAllPerson } from '~/pages/sts/entities/input/enrollNumberAllPerson';
import { EnrollNumberDetailIsSts } from '~/pages/sts/entities/input/enrollNumberDetailIsSts';
import { EnrollNumberAllPersonOutput } from '~/pages/sts/entities/output/enrollNumberAllPersonOutput';
import { EnrollNumberDetailIsStsOutput } from '~/pages/sts/entities/output/enrollNumberDetailIsStsOutput';
import {
    LoadEnrollNumberDetailIsSts,
    LoadEnrollNumbers,
    StartEnrollNumbersStsFilter
} from '~/pages/sts/state-mgmt/sts.actions';

export interface StsStateModel {
    loadingEnrollNumbers: boolean;
    loadingIsStsFilter: boolean;
    enrollNumbersToFilter: number;
    enrollNumbers: EnrollNumberAllPersonOutput[];
}

const initialStateModel: StsStateModel = {
    loadingEnrollNumbers: false,
    loadingIsStsFilter: false,
    enrollNumbersToFilter: 0,
    enrollNumbers: []
};

@State<StsStateModel>({
    name: 'sts',
    defaults: initialStateModel
})

export class StsState {

    @Selector()
    static getEnrollNumbers(state: StsStateModel) {
        return state.enrollNumbers;
    }

    @Selector()
    static isLoading(state: StsStateModel) {
        return state.loadingEnrollNumbers || state.loadingIsStsFilter;
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load enroll numbers, if successful, then dispatch action for filtering loaded numbers
     *
     * @param {StateContext<StsStateModel>} ctx
     * @param {LoadEnrollNumbers} action
     * @returns {Observable<any>}
     */
    @Action(LoadEnrollNumbers)
    loadEnrollNumbers(ctx: StateContext<StsStateModel>, action: LoadEnrollNumbers) {
        ctx.patchState({
            loadingEnrollNumbers: true
        });

        return this.webApiService.call(
            new EnrollNumberAllPerson(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_PERSON_ID)),
            () => new EnrollNumberAllPersonOutput(),
            wsTelephony
        ).pipe(
            tap((response: EnrollNumberAllPersonOutput[]) => {
                ctx.patchState({
                    loadingEnrollNumbers: false,
                    enrollNumbers: response
                });

                ctx.dispatch(new StartEnrollNumbersStsFilter(response.length));
            }),
            catchError(e => {
                ctx.patchState({
                    loadingEnrollNumbers: false,
                    enrollNumbers: initialStateModel.enrollNumbers
                });

                return e;
            })
        );
    }

    /**
     * Started loadingIsStsFilter and set number of numbers which should be processed
     * Then dispatch LoadEnrollNumberDetailIsSts action for every number
     *
     * @param {StateContext<StsStateModel>} ctx
     * @param {StartEnrollNumbersStsFilter} action
     * @returns {Observable<void>}
     */
    @Action(StartEnrollNumbersStsFilter)
    startEnrollNumbersStsFilter(ctx: StateContext<StsStateModel>, action: StartEnrollNumbersStsFilter) {
        if (action.count) {
            ctx.patchState({
                enrollNumbersToFilter: action.count,
                loadingIsStsFilter: true
            });

            return ctx.dispatch(
                ctx.getState().enrollNumbers
                    .map((enrollNumber: EnrollNumberAllPersonOutput) => {
                        return new LoadEnrollNumberDetailIsSts(enrollNumber.DisplayName);
                    })
            );
        }
    }

    /**
     * Load info about number, If is in STS. According to leave or remove number from enrollNumbers and update loading properties
     *
     * @param {StateContext<StsStateModel>} ctx
     * @param {LoadEnrollNumberDetailIsSts} action
     * @returns {Observable<any>}
     */
    @Action(LoadEnrollNumberDetailIsSts)
    loadEnrollNumberDetailIsSts(ctx: StateContext<StsStateModel>, action: LoadEnrollNumberDetailIsSts) {
        if (action.enrollNumber) {
            return this.webApiService.call(
                new EnrollNumberDetailIsSts(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.enrollNumber),
                () => new EnrollNumberDetailIsStsOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollNumberDetailIsStsOutput[]) => {
                    const isEnrollNumberSts = response.length > 0 ? response[0].IsSts : false;
                    let newEnrollNumbers;
                    if (isEnrollNumberSts) {
                        newEnrollNumbers = ctx.getState().enrollNumbers;
                    } else {
                        newEnrollNumbers = ctx.getState().enrollNumbers.filter((enrollNumber: EnrollNumberAllPersonOutput) =>
                            enrollNumber.DisplayName !== action.enrollNumber);
                    }

                    ctx.patchState({
                        enrollNumbersToFilter: ctx.getState().enrollNumbersToFilter - 1,
                        loadingIsStsFilter: (ctx.getState().enrollNumbersToFilter - 1) !== 0,
                        enrollNumbers: newEnrollNumbers
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        enrollNumbersToFilter: ctx.getState().enrollNumbersToFilter - 1,
                        loadingIsStsFilter: (ctx.getState().enrollNumbersToFilter - 1) !== 0,
                        enrollNumbers: ctx.getState().enrollNumbers.filter((enrollNumber: EnrollNumberAllPersonOutput) =>
                            enrollNumber.DisplayName !== action.enrollNumber)
                    });

                    throw e;
                })
            );
        }
    }
}
