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 { EnrollNumberAllUsage } from '~/pages/sts/entities/input/enrollNumberAllUsage';
import { EnrollNumberDetailIsSts } from '~/pages/sts/entities/input/enrollNumberDetailIsSts';
import { EnrollNumberAllPersonOutput } from '~/pages/sts/entities/output/enrollNumberAllPersonOutput';
import { EnrollNumberAllUsageOutput } from '~/pages/sts/entities/output/enrollNumberAllUsageOutput';
import { EnrollNumberDetailIsStsOutput } from '~/pages/sts/entities/output/enrollNumberDetailIsStsOutput';
import {
    LoadEnrollNumberUsages,
    LoadStatsEnrollNumberDetailIsSts,
    LoadStatsEnrollNumbers,
    StartStatsEnrollNumbersStsFilter
} from '~/pages/sts/state-mgmt/sts-detail-stats.actions';

export interface StsDetailStatsStateModel {
    loadingEnrollNumbers: boolean;
    loadingIsStsFilter: boolean;
    enrollNumbersToFilter: number;
    loadingEnrollNumberUsages: boolean;
    enrollNumbers: EnrollNumberAllPersonOutput[];
    enrollNumberUsages: EnrollNumberAllUsageOutput[];
}

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

@State<StsDetailStatsStateModel>({
    name: 'stsDetailStats',
    defaults: initialStateModel
})

export class StsDetailStatsState {

    @Selector()
    static getStatsEnrollNumbers(state: StsDetailStatsStateModel) {
        return state.enrollNumbers;
    }

    @Selector()
    static getEnrollNumberUsages(state: StsDetailStatsStateModel) {
        return state.enrollNumberUsages;
    }

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

    constructor(
        private webApiService: WebApiService
    ) {
    }

    /**
     * Load enroll numbers, if successful, then dispatch action for filtering loaded numbers
     *
     * @param {StateContext<StsDetailStatsStateModel>} ctx
     * @param {LoadStatsEnrollNumbers} action
     * @returns {Observable<any>}
     */
    @Action(LoadStatsEnrollNumbers)
    loadStatsEnrollNumbers(ctx: StateContext<StsDetailStatsStateModel>, action: LoadStatsEnrollNumbers) {
        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 StartStatsEnrollNumbersStsFilter(response.length));
            }),
            catchError(e => {
                ctx.patchState({
                    loadingEnrollNumbers: false,
                    enrollNumbers: initialStateModel.enrollNumbers
                });

                throw e;
            })
        );
    }

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

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

    /**
     * Load info about number, If is in STS. According to leave or remove number from enrollNumbers and update loading properties
     *
     * @param {StateContext<StsDetailStatsStateModel>} ctx
     * @param {LoadStatsEnrollNumberDetailIsSts} action
     * @returns {Observable<any>}
     */
    @Action(LoadStatsEnrollNumberDetailIsSts)
    loadStatsEnrollNumberDetailIsSts(ctx: StateContext<StsDetailStatsStateModel>, action: LoadStatsEnrollNumberDetailIsSts) {
        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;
            })
        );
    }

    /**
     * Load enrollNumberUsages, filtering only last three items a save it to state.
     *
     * @param {StateContext<StsDetailStatsStateModel>} ctx
     * @param {LoadEnrollNumberUsages} action
     * @returns {Observable<any>}
     */
    @Action(LoadEnrollNumberUsages)
    loadEnrollNumberUsages(ctx: StateContext<StsDetailStatsStateModel>, action: LoadEnrollNumberUsages) {
        ctx.patchState({
            loadingEnrollNumberUsages: true
        });

        return this.webApiService.call(
            new EnrollNumberAllUsage(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.phoneId),
            () => new EnrollNumberAllUsageOutput(),
            wsTelephony
        ).pipe(
            tap((response: EnrollNumberAllUsageOutput[]) => {
                const enrollNumberUsages = response
                    .filter((e: EnrollNumberAllUsageOutput) => {
                        const todayWithoutXMonth = new Date();
                        todayWithoutXMonth.setDate(1);
                        todayWithoutXMonth.setMonth(todayWithoutXMonth.getMonth() - 4);

                        return new Date(+e.Year, +e.Month - 1) >= todayWithoutXMonth;
                    });

                ctx.patchState({
                    loadingEnrollNumberUsages: false,
                    enrollNumberUsages
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingEnrollNumberUsages: false,
                    enrollNumberUsages: initialStateModel.enrollNumberUsages
                });

                throw e;
            })
        );
    }

}
