import { Action, Selector, State, StateContext } from '@ngxs/store';
import { tap, catchError } from 'rxjs/operators';
import { wsOrganizationUnit, wsEvents } from '~/constants/api.constants';
import { USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { ApplicationSettings as AppSettings } from '@nativescript/core';

import { CampEventLoadDegrees, CampEventParticipantResetSearch, CampEventUpdateParticipant, CampParticipantSearchPerson, InsertCampEventParticipant, InsertMultiCampEventParticipant, LoadCampEventPersonMulti } from './camp-event-participant.actions';
import { PersonAllEventCamp, CampEventPersonOutput, ParticipantCampInsert, ParticipantCampInsertOutput, ParticipantCampUpdate, DegreeTypeAll, Degree, CampEventMultiPersonOutput, PersonAllEventCampMulti } from '../../entities/camp-event-participant.types';
import { FeedbackType } from 'nativescript-feedback';
import { feedbackMessage } from '~/pages/material/utils/feedback-messages';
import { errorFeedbackOperator } from '../gen/gen-event-new.state';
import { CampEventDetailStateModel } from './camp-event-detail.state';
import { CampEventUpdateParticipantList } from './camp-event-detail.actions';
import { zip } from 'rxjs';
import { errorFeedback } from '~/pages/event/state-mgmt/gen/gen-event-new.state';


export interface NewParticipant {
    lastName: string;
    firstName: string;
    nickName: string;
    note: string;
    degrees: Degree[] | undefined;
    contacts: string[] | undefined;
}


export interface CampEventParticipantNewStateModel {
    newParticipant: ParticipantCampInsertOutput,
    personList: CampEventPersonOutput[],
    degrees: Degree[]
    multiPersonList: CampEventMultiPersonOutput[]
}


const initialStateModel: CampEventParticipantNewStateModel = {
    personList: [],
    newParticipant: null,
    degrees: [],
    multiPersonList: [],
};


@State<CampEventParticipantNewStateModel>({
    name: 'CampEventParticipantNew',
    defaults: initialStateModel
})

export class CampEventParticipantState {
    @Selector()
    static getPersonList(state: CampEventParticipantNewStateModel) {
        return state.personList;
    }
    @Selector()
    static getNewParticipant(state: CampEventParticipantNewStateModel) {
        return state.newParticipant;
    }
    @Selector()
    static getDegrees(state: CampEventParticipantNewStateModel) {
        return state.degrees;
    }
    @Selector()
    static getMultiPersonList(state: CampEventParticipantNewStateModel) {
        return state.multiPersonList;
    }
    constructor(
        private webApiService: WebApiService
    ) {
    }


    @Action(CampParticipantSearchPerson)
    searchPerson(ctx: StateContext<CampEventParticipantNewStateModel>, { payload }: CampParticipantSearchPerson) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new PersonAllEventCamp(tk, payload.eventId);
        input[payload.criteria] = payload.text;
        return this.webApiService.call(input,
            () => new CampEventPersonOutput(),
            wsOrganizationUnit
        ).pipe(
            tap((response: CampEventPersonOutput[]) => {
                ctx.patchState({
                    personList: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    personList: initialStateModel.personList
                });

                throw e;
            })
        );
    }


    @Action(InsertMultiCampEventParticipant)
    insertMultiParticipant(ctx: StateContext<CampEventParticipantNewStateModel>,
        { personIdList, campId }: InsertMultiCampEventParticipant) {
        const tk = AppSettings.getString(USER_TOKEN)

        const pplArr = personIdList.map(p => new ParticipantCampInsert(tk, campId, p));

        const reqs = pplArr.map(p => this.webApiService.call(p,
            () => new ParticipantCampInsertOutput(),
            wsEvents
        ));

        ctx.patchState({ newParticipant: null })
        return zip(...reqs).pipe(
            tap((response: ParticipantCampInsertOutput[][]) => {
                if (response.length > 0 && response[0].length > 0)
                    ctx.patchState({ newParticipant: response[0][0], personList: [] })
                feedbackMessage(FeedbackType.Success, 'Účastníci tábora přidány', `Účastníci tábora byli úspěšně přidány (${reqs.length})`)
            }),
            errorFeedbackOperator('InsertMultiCampEventParticipantFail')
        );

    }
    @Action(InsertCampEventParticipant)
    insertParticipant(ctx: StateContext<CampEventParticipantNewStateModel>,
        { payload }: InsertCampEventParticipant) {
        const tk = AppSettings.getString(USER_TOKEN)

        const { personId, newParticip, campId } = payload
        const input = new ParticipantCampInsert(tk, campId)
        if (personId) {
            input.ID_Person = personId
        } else if (newParticip) {
            const { firstName, lastName, nickName, note, degrees } = newParticip
            input.Person = {
                FirstName: firstName, LastName: lastName,
                NickName: nickName, Note: note, Degrees: degrees
            }
        }
        ctx.patchState({ newParticipant: null })
        return this.webApiService.call(input,
            () => new ParticipantCampInsertOutput(),
            wsEvents
        ).pipe(
            tap((response: ParticipantCampInsertOutput[]) => {
                if (response.length === 1) {
                    ctx.patchState({ newParticipant: response[0], personList: [] })
                    feedbackMessage(FeedbackType.Success, 'Účastník tábora přidán', 'Účastník tábora byl úspěšně přidán')
                    return "Účastník tábora byl úspěšně přidán"
                }
                errorFeedback('InsertCampEventParticipantFail')
                throw "Nepodařilo se přidat učastníka tábora"
            }),
            errorFeedbackOperator('InsertCampEventParticipantFail')
        );

    }



    @Action(CampEventParticipantResetSearch)
    resetSearch(ctx: StateContext<CampEventParticipantNewStateModel>) {
        ctx.patchState({ personList: [] })
    }
    @Action(CampEventUpdateParticipant)
    updateParticipant(ctx: StateContext<CampEventDetailStateModel>, { payload }: CampEventUpdateParticipant) {
        if (payload) {
            const { ID, Days, Real, Estimate, Note, } = payload.particip
            const model = new ParticipantCampUpdate(AppSettings.getString(USER_TOKEN), ID, Estimate, Real, Days, Note)

            return this.webApiService.call(model,
                () => ({}),
                wsEvents
            ).pipe(
                tap(() => {
                    ctx.dispatch(new CampEventUpdateParticipantList(payload.particip))
                    feedbackMessage(FeedbackType.Success, 'Účastník upraven.', `Id: ${model.ID}`)
                }),
                errorFeedbackOperator('CampEventUpdateParticipant')
            );
        }

    }
    @Action(CampEventLoadDegrees)
    loadDegrees(ctx: StateContext<CampEventParticipantNewStateModel>) {
        return this.webApiService.call(new DegreeTypeAll(),
            () => new Degree(),
            wsOrganizationUnit
        ).pipe(
            tap((res: Degree[]) => {
                ctx.patchState({
                    degrees: res
                });
            }),
            errorFeedbackOperator('CampEventLoadDegrees')
        );


    }

    @Action(LoadCampEventPersonMulti)
    loadEventDetail(ctx: StateContext<CampEventParticipantNewStateModel>,
        action: LoadCampEventPersonMulti) {
        const tk = AppSettings.getString(USER_TOKEN);
        if (action.campId) {
            return this.webApiService.call(
                new PersonAllEventCampMulti(tk, action.campId),
                () => new CampEventMultiPersonOutput(),
                wsOrganizationUnit
            ).pipe(
                tap((response: CampEventMultiPersonOutput[]) => {
                    ctx.patchState({
                        multiPersonList: response
                    });

                }),
                catchError(e => {
                    ctx.patchState({
                        multiPersonList: initialStateModel.multiPersonList
                    });

                    throw e;
                })
            );
        }
    }


}
