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 { EnrollInvoiceAllPerson } from '~/pages/sts/entities/input/enrollInvoiceAllPerson';
import { EnrollInvoiceItemAll } from '~/pages/sts/entities/input/enrollInvoiceItemAll';
import { EnrollInvoiceAllPersonOutput } from '~/pages/sts/entities/output/enrollInvoiceAllPersonOutput';
import { EnrollInvoiceItemAllOutput } from '~/pages/sts/entities/output/enrollInvoiceItemAllOutput';
import { StatsDataBase } from '~/pages/sts/entities/stats-data-base';
import { LoadStatsEnrollInvoiceItems, LoadStatsEnrollInvoices } from '~/pages/sts/state-mgmt/sts-stats.actions';
import { DateTimePipe } from '~/shared/pipes/date-time.pipe';

export interface StsStatsStateModel {
    loadingEnrollInvoices: boolean;
    loadingStatsDataBase: boolean;
    statsDataBaseToLoad: number;
    enrollInvoices: EnrollInvoiceAllPersonOutput[];
    statsDataBase: StatsDataBase[];
}

const initialStateModel: StsStatsStateModel = {
    loadingEnrollInvoices: false,
    loadingStatsDataBase: false,
    statsDataBaseToLoad: 0,
    enrollInvoices: [],
    statsDataBase: []
};

@State<StsStatsStateModel>({
    name: 'stsStats',
    defaults: initialStateModel
})

export class StsStatsState {

    @Selector()
    static getStatsEnrollInvoices(state: StsStatsStateModel) {
        return state.enrollInvoices;
    }

    @Selector()
    static getStatsDataBase(state: StsStatsStateModel) {
        return state.statsDataBase;
    }

    @Selector()
    static isLoading(state: StsStatsStateModel) {
        return state.loadingEnrollInvoices || state.loadingStatsDataBase;
    }

    constructor(
        private webApiService: WebApiService,
        private dateTimePipe: DateTimePipe
    ) {
    }

    /**
     * Load invoices. Sorting that by date (year, month) (descending) and leave only last three,
     * which are save to state and actions for loading invoice items are dispatched.
     * It sets nomber of items, which should be loaded
     *
     * I using DateTime pipe for transform date
     *
     * @param {StateContext<StsStatsStateModel>} ctx
     * @param {LoadStatsEnrollInvoices} action
     * @returns {Observable<any>}
     */
    @Action(LoadStatsEnrollInvoices)
    loadStatsEnrollInvoices(ctx: StateContext<StsStatsStateModel>, action: LoadStatsEnrollInvoices) {
        ctx.patchState({
            loadingEnrollInvoices: true
        });

        return this.webApiService.call(
            new EnrollInvoiceAllPerson(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_PERSON_ID)),
            () => new EnrollInvoiceAllPersonOutput(),
            wsTelephony
        ).pipe(
            tap((response: EnrollInvoiceAllPersonOutput[]) => {
                const lastThreeEi = response
                    .sort((eIA: EnrollInvoiceAllPersonOutput, eIB: EnrollInvoiceAllPersonOutput) => {
                        const [dateA, timeA] = eIA.DateFrom.split('T');
                        const [dateB, timeB] = eIB.DateFrom.split('T');
                        const dateObjA = new Date(dateA);
                        const dateObjB = new Date(dateB);

                        return dateObjA === dateObjB ? 0 : dateObjA > dateObjB ? -1 : 11;
                    })
                    .slice(0, 3);

                ctx.patchState({
                    loadingEnrollInvoices: false,
                    enrollInvoices: lastThreeEi,
                    statsDataBaseToLoad: lastThreeEi.length,
                    loadingStatsDataBase: lastThreeEi.length !== 0,
                    statsDataBase: initialStateModel.statsDataBase
                });
                ctx.dispatch(
                    lastThreeEi.map((enrollInvoice: EnrollInvoiceAllPersonOutput) => {
                        return new LoadStatsEnrollInvoiceItems(enrollInvoice.ID, this.dateTimePipe.transform(enrollInvoice.DateFrom, false, 2));
                    })
                );
            }),
            catchError(e => {
                ctx.patchState({
                    loadingEnrollInvoices: false,
                    enrollInvoices: initialStateModel.enrollInvoices,
                    statsDataBase: initialStateModel.statsDataBase,
                    statsDataBaseToLoad: initialStateModel.statsDataBaseToLoad,
                    loadingStatsDataBase: initialStateModel.loadingStatsDataBase
                });

                throw e;
            })
        );
    }

    /**
     * It load items of invoices. Update loading properties and response is added to statsDateBase using StatsDateBase entity,
     * which specify type for using data in chart and data table
     *
     * @param {StateContext<StsStatsStateModel>} ctx
     * @param {LoadStatsEnrollInvoiceItems} action
     * @returns {Observable<any>}
     */
    @Action(LoadStatsEnrollInvoiceItems)
    loadStatsEnrollInvoiceItems(ctx: StateContext<StsStatsStateModel>, action: LoadStatsEnrollInvoiceItems) {
        if (action.enrollInvoiceId) {
            return this.webApiService.call(
                new EnrollInvoiceItemAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.enrollInvoiceId),
                () => new EnrollInvoiceItemAllOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollInvoiceItemAllOutput[]) => {
                    const state = ctx.getState();
                    ctx.patchState({
                        statsDataBase: [
                            ...state.statsDataBase,
                            ...response.map((enrollInvoiceItem: EnrollInvoiceItemAllOutput) =>
                                new StatsDataBase(
                                    action.enrollInvoiceId,
                                    action.enrollInvoiceDate,
                                    Math.round(enrollInvoiceItem.PriceWithVat),
                                    enrollInvoiceItem.EnrollNumber
                                )
                            )
                        ],
                        statsDataBaseToLoad: state.statsDataBaseToLoad - 1,
                        loadingStatsDataBase: (state.statsDataBaseToLoad - 1) !== 0
                    });
                }),
                catchError(e => {
                    const state = ctx.getState();
                    ctx.patchState({
                        statsDataBaseToLoad: state.statsDataBaseToLoad - 1,
                        loadingStatsDataBase: (state.statsDataBaseToLoad - 1) !== 0
                    });

                    throw e;
                })
            );
        }
    }
}
