import { RouterExtensions } from '@nativescript/angular';
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 { transitionOptions } from '~/constants/shared.constants';
import { WebApiService } from '~/core/services/web-api.service';
import { EnrollNumberAllPerson } from '~/pages/sts/entities/input/enrollNumberAllPerson';
import { EnrollNumberDetail } from '~/pages/sts/entities/input/enrollNumberDetail';
import { EnrollNumberServiceAll } from '~/pages/sts/entities/input/enrollNumberServiceAll';
import { EnrollNumberUpdateFup } from '~/pages/sts/entities/input/enrollNumberUpdateFup';
import { FupTypeAll } from '~/pages/sts/entities/input/fupTypeAll';
import { TariffDetail } from '~/pages/sts/entities/input/tariffDetail';
import { TariffServiceAll } from '~/pages/sts/entities/input/tariffServiceAll';
import { EnrollNumberAllPersonOutput } from '~/pages/sts/entities/output/enrollNumberAllPersonOutput';
import { EnrollNumberDetailOutput } from '~/pages/sts/entities/output/enrollNumberDetailOutput';
import { EnrollNumberServiceAllOutput } from '~/pages/sts/entities/output/enrollNumberServiceAllOutput';
import { EnrollNumberUpdateFupOutput } from '~/pages/sts/entities/output/enrollNumberUpdateFupOutput';
import { FupTypeAllOutput } from '~/pages/sts/entities/output/fupTypeAllOutput';
import { TariffDetailOutput } from '~/pages/sts/entities/output/tariffDetailOutput';
import { TariffServiceAllOutput } from '~/pages/sts/entities/output/tariffServiceAllOutput';
import { TariffNumberService } from '~/pages/sts/entities/tariff-number-service';
import {
    CreateEnrollNumberUpdateFup,
    LoadEnrollNumber,
    LoadEnrollNumberDetail,
    LoadEnrollNumberServices,
    LoadFupTypes,
    LoadTariffDetail,
    LoadTariffServices
} from '~/pages/sts/state-mgmt/sts-detail.actions';

export interface StsDetailStateModel {
    loadingEnrollNumber: boolean;
    loadingEnrollNumberDetail: boolean;
    loadingTariffDetail: boolean;
    loadingTariffServices: boolean;
    loadingEnrollNumberServices: boolean;
    loadingFupTypes: boolean;
    loadingCreateEnrollNumberUpdateFup: boolean;
    enrollNumber: EnrollNumberAllPersonOutput;
    enrollNumberDetail: EnrollNumberDetailOutput;
    tariffDetail: TariffDetailOutput;
    tariffServices: TariffServiceAllOutput[];
    enrollNumberServices: EnrollNumberServiceAllOutput[];
    fupTypes: FupTypeAllOutput[];
}

const initialStateModel: StsDetailStateModel = {
    loadingEnrollNumber: false,
    loadingEnrollNumberDetail: false,
    loadingTariffDetail: false,
    loadingTariffServices: false,
    loadingEnrollNumberServices: false,
    loadingFupTypes: false,
    loadingCreateEnrollNumberUpdateFup: false,
    enrollNumber: null,
    enrollNumberDetail: null,
    tariffDetail: null,
    tariffServices: [],
    enrollNumberServices: [],
    fupTypes: []
};

@State<StsDetailStateModel>({
    name: 'stsDetail',
    defaults: initialStateModel
})
export class StsDetailState {

    @Selector()
    static getEnrollNumber(state: StsDetailStateModel) {
        return state.enrollNumber;
    }

    @Selector()
    static getEnrollNumberDetail(state: StsDetailStateModel) {
        return state.enrollNumberDetail;
    }

    @Selector()
    static getTariffDetail(state: StsDetailStateModel) {
        return state.tariffDetail;
    }

    @Selector()
    static getTariffServices(state: StsDetailStateModel) {
        return state.tariffServices;
    }

    @Selector()
    static getEnrollNumberServices(state: StsDetailStateModel) {
        return state.enrollNumberServices;
    }

    /**
     * It use enrollNumberServices and tariffServices state to return array of enrollNumberServices
     * with text Ano/Ne signifying If number has service
     *
     * @param {StsDetailStateModel} state
     * @returns {TariffNumberService[]}
     */
    @Selector()
    static getTariffServicesWithNumberServices(state: StsDetailStateModel) {
        return state.tariffServices.map((tSrv: TariffServiceAllOutput) => {
            if (state.enrollNumberServices.find(e => e.ID_TariffService === tSrv.ID)) {
                return new TariffNumberService(tSrv.ID, tSrv.DisplayName, tSrv.TrueText, tSrv.FalseText, 'Ano');
            } else {
                return new TariffNumberService(tSrv.ID, tSrv.DisplayName, tSrv.TrueText, tSrv.FalseText, 'Ne');
            }
        });
    }

    @Selector()
    static getFupTypes(state: StsDetailStateModel) {
        return state.fupTypes;
    }

    @Selector()
    static isLoading(state: StsDetailStateModel) {
        return state.loadingEnrollNumber
            || state.loadingEnrollNumberDetail
            || state.loadingTariffDetail
            || state.loadingTariffServices
            || state.loadingEnrollNumberServices
            || state.loadingFupTypes
            || state.loadingCreateEnrollNumberUpdateFup;
    }

    constructor(
        private webApiService: WebApiService,
        private routerExtensions: RouterExtensions
    ) {
    }

    /**
     * Load enroll number specify in action payload. Setting state and dispatch actions for load next info.
     * If number was not loaded then setting state and navigate to /sts
     *
     * @param {StateContext<StsDetailStateModel>} ctx
     * @param {LoadEnrollNumber} action
     * @returns {Observable<any>}
     */
    @Action(LoadEnrollNumber)
    loadEnrollNumber(ctx: StateContext<StsDetailStateModel>, action: LoadEnrollNumber) {
        ctx.patchState({
            loadingEnrollNumber: true
        });

        if (action.phoneNumber) {
            return this.webApiService.call(
                new EnrollNumberAllPerson(APP_ID, ApplicationSettings.getString(USER_TOKEN), ApplicationSettings.getNumber(USER_PERSON_ID), action.phoneNumber),
                () => new EnrollNumberAllPersonOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollNumberAllPersonOutput[]) => {
                    const actions: any = [];
                    if (response.length === 1) {
                        ctx.patchState({
                            loadingEnrollNumber: false,
                            enrollNumber: response[0],
                            tariffDetail: initialStateModel.tariffDetail,
                            tariffServices: initialStateModel.tariffServices,
                            enrollNumberServices: initialStateModel.enrollNumberServices
                        });
                        actions.push(new LoadEnrollNumberDetail(response[0].ID));
                        actions.push(new LoadTariffDetail(response[0].ID_Tariff));
                        actions.push(new LoadTariffServices());
                        actions.push(new LoadEnrollNumberServices(response[0].ID));
                    } else {
                        ctx.patchState({
                            loadingEnrollNumber: false,
                            enrollNumber: initialStateModel.enrollNumber,
                            tariffDetail: initialStateModel.tariffDetail,
                            tariffServices: initialStateModel.tariffServices,
                            enrollNumberServices: initialStateModel.enrollNumberServices
                        });
                        this.routerExtensions.navigate(['/sts'], { transition: transitionOptions });
                        throw new Error('Nepodařilo se načíst detail pro dané číslo');
                    }

                    ctx.dispatch(actions);
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingEnrollNumber: false,
                        enrollNumber: initialStateModel.enrollNumber,
                        tariffDetail: initialStateModel.tariffDetail,
                        tariffServices: initialStateModel.tariffServices,
                        enrollNumberServices: initialStateModel.enrollNumberServices
                    });

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

    /**
     * Load enroll number detail which contains more data then enrollNumberAllPerson
     *
     * @param {StateContext<StsDetailStateModel>} ctx
     * @param {LoadEnrollNumberDetail} action
     * @returns {Observable<any>}
     */
    @Action(LoadEnrollNumberDetail)
    loadEnrollNumberDetail(ctx: StateContext<StsDetailStateModel>, action: LoadEnrollNumberDetail) {
        ctx.patchState({
            loadingEnrollNumberDetail: true
        });

        if (action.enrollNumberId) {
            return this.webApiService.call(
                new EnrollNumberDetail(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.enrollNumberId),
                () => new EnrollNumberDetailOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollNumberDetailOutput[]) => {
                    if (response.length === 1) {
                        ctx.patchState({
                            enrollNumberDetail: response[0],
                            loadingEnrollNumberDetail: false
                        });
                    } else {
                        ctx.patchState({
                            enrollNumberDetail: initialStateModel.enrollNumberDetail,
                            loadingEnrollNumberDetail: false
                        });
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingEnrollNumberDetail: false
                    });

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

    @Action(LoadTariffDetail)
    loadTariffDetail(ctx: StateContext<StsDetailStateModel>, action: LoadTariffDetail) {
        ctx.patchState({
            loadingTariffDetail: true
        });

        if (action.tariffId) {
            return this.webApiService.call(
                new TariffDetail(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.tariffId),
                () => new TariffDetailOutput(),
                wsTelephony
            ).pipe(
                tap((response: TariffDetailOutput[]) => {
                    if (response.length === 1) {
                        ctx.patchState({
                            loadingTariffDetail: false,
                            tariffDetail: response[0]
                        });
                    } else {
                        ctx.patchState({
                            loadingTariffDetail: false,
                            tariffDetail: initialStateModel.tariffDetail
                        });
                        throw new Error('Nepodařilo se načíst detail tarifu');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingTariffDetail: false,
                        tariffDetail: initialStateModel.tariffDetail
                    });

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

    @Action(LoadTariffServices)
    loadTariffServices(ctx: StateContext<StsDetailStateModel>, action: LoadTariffServices) {
        ctx.patchState({
            loadingTariffServices: true
        });

        return this.webApiService.call(
            new TariffServiceAll(APP_ID, ApplicationSettings.getString(USER_TOKEN)),
            () => new TariffServiceAllOutput(),
            wsTelephony
        ).pipe(
            tap((response: TariffServiceAllOutput[]) => {
                ctx.patchState({
                    loadingTariffServices: false,
                    tariffServices: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingTariffServices: false,
                    tariffServices: initialStateModel.tariffServices
                });

                throw e;
            })
        );
    }

    @Action(LoadEnrollNumberServices)
    loadEnrollNumberServices(ctx: StateContext<StsDetailStateModel>, action: LoadEnrollNumberServices) {
        ctx.patchState({
            loadingEnrollNumberServices: true
        });

        if (action.enrollNumberId) {
            return this.webApiService.call(
                new EnrollNumberServiceAll(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.enrollNumberId),
                () => new EnrollNumberServiceAllOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollNumberServiceAllOutput[]) => {
                    ctx.patchState({
                        loadingEnrollNumberServices: false,
                        enrollNumberServices: response
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingEnrollNumberServices: false,
                        enrollNumberServices: initialStateModel.enrollNumberServices
                    });

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

    @Action(LoadFupTypes)
    loadFupTypes(ctx: StateContext<StsDetailStateModel>, action: LoadFupTypes) {
        ctx.patchState({
            loadingFupTypes: true
        });

        return this.webApiService.call(
            new FupTypeAll(APP_ID, ApplicationSettings.getString(USER_TOKEN)),
            () => new FupTypeAllOutput(),
            wsTelephony
        ).pipe(
            tap((response: FupTypeAllOutput[]) => {
                ctx.patchState({
                    loadingFupTypes: false,
                    fupTypes: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    loadingFupTypes: false,
                    fupTypes: initialStateModel.fupTypes
                });

                throw e;
            })
        );
    }

    /**
     * It create request for increase fup limit
     *
     * @param {StateContext<StsDetailStateModel>} ctx
     * @param {CreateEnrollNumberUpdateFup} action
     * @returns {Observable<any>}
     */
    @Action(CreateEnrollNumberUpdateFup)
    createEnrollNumberUpdateFup(ctx: StateContext<StsDetailStateModel>, action: CreateEnrollNumberUpdateFup) {
        ctx.patchState({
            loadingCreateEnrollNumberUpdateFup: true
        });

        if (action.enrollNumberId && action.fupTypeId) {
            return this.webApiService.call(
                new EnrollNumberUpdateFup(APP_ID, ApplicationSettings.getString(USER_TOKEN), action.enrollNumberId, action.fupTypeId),
                () => new EnrollNumberUpdateFupOutput(),
                wsTelephony
            ).pipe(
                tap((response: EnrollNumberUpdateFupOutput) => {
                    // TODO FIX update fup
                    ctx.patchState({
                        loadingCreateEnrollNumberUpdateFup: false
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingCreateEnrollNumberUpdateFup: false
                    });
                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingCreateEnrollNumberUpdateFup: false
            });
        }
    }

}
