import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { ApplicationSettings as AppSettings } from '@nativescript/core';

import { APP_ID, wsEvents, wsOrganizationUnit } from '~/constants/api.constants';
import { USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { CampEventDetailOutput, CampEventFunctionAllOutput, CampEventStatisticDetail, CampEventUpdateFunctionOutput, EventCampDetail, EventCampStatisticDetail, EventCampStatisticDetailOutput, EventCampUpdateFunction, EventFunctionAllCamp, ParticipantCampAll } from '../../entities/camp-event-detail.types';
import { CampEventRemoveParticipant, CampEventUpdateFunctions, CampEventUpdateParticipantList, LoadCampEventDetail, LoadCampEventLeaders, LoadCampEventParticipants, LoadCampEventStatisticDetail, LoadCampUnits, SetCampEventParticipantSortParams } from './camp-event-detail.actions';
import { CampEventParticipantAllOutput } from './../../entities/camp-event-detail.types';
import { zip } from 'rxjs';
import { UnitDetailOutput } from '~/pages/unit/entities/output/unitDetailOutput';
import { UnitDetail } from '~/pages/unit/entities/input/unitDetail';
import { CampParticipantSortKey, SortDirection, SortParams } from '../../types/EventSorting';
import { ParticipantCampDelete } from '../../entities/camp-event-participant.types';
import { FeedbackType } from 'nativescript-feedback';
import { feedbackMessage } from '~/pages/material/utils/feedback-messages';
import { errorFeedback, errorFeedbackOperator } from '../gen/gen-event-new.state';


const CampEventFunctionNames = {
    "Vedoucí tábora": "Leader",
    "Zástupce vedoucího tábora": "Assistant",
    "Hospodář": "Economist",
    "Zdravotník": "Medic",
}
export interface CampEventDetailStateModel {
    eventDetail: CampEventDetailOutput;
    leaderList: CampEventFunctionAllOutput[];
    participants: CampEventParticipantAllOutput[];
    statisticDetail: CampEventStatisticDetail;
    campUnits: UnitDetailOutput[];
    campParticipantsSortParams: SortParams;
}

const initialStateModel: CampEventDetailStateModel = {
    eventDetail: null,
    leaderList: [],
    participants: [],
    statisticDetail: null,
    campUnits: [],
    campParticipantsSortParams: { sortByKey: CampParticipantSortKey.NAME, sortDirection: SortDirection.ASC },

};

@State<CampEventDetailStateModel>({
    name: 'campEventDetail',
    defaults: initialStateModel
})
export class CampEventDetailState {
    @Selector()
    static getEventDetail(state: CampEventDetailStateModel) {
        return state.eventDetail;
    }
    @Selector()
    static getEventLeaderDetail(state: CampEventDetailStateModel) {
        return state.leaderList
    }

    @Selector()
    static getParticipants(state: CampEventDetailStateModel) {
        return state.participants
    }
    @Selector()
    static getStatisticDetail(state: CampEventDetailStateModel) {
        return state.statisticDetail
    }
    @Selector()
    static getCampUnits(state: CampEventDetailStateModel) {
        return state.campUnits
    }
    @Selector()
    static getCampParticipantsSortParams(state: CampEventDetailStateModel) {
        return state.campParticipantsSortParams;
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }
    @Action(SetCampEventParticipantSortParams)
    setSortParams(ctx: StateContext<CampEventDetailStateModel>,
        { payload }: SetCampEventParticipantSortParams) {
        ctx.patchState({
            campParticipantsSortParams: payload || { ...initialStateModel.campParticipantsSortParams }
        })
    }

    @Action(LoadCampEventDetail)
    loadEventDetail(ctx: StateContext<CampEventDetailStateModel>, action: LoadCampEventDetail) {
        const tk = AppSettings.getString(USER_TOKEN);
        if (action.id) {
            return this.webApiService.call(
                new EventCampDetail(tk, action.id),
                () => new CampEventDetailOutput(),
                wsEvents
            ).pipe(
                tap((response: CampEventDetailOutput[]) => {
                    if (response.length === 1) {
                        ctx.patchState({
                            eventDetail: response[0]
                        });
                    } else {
                        ctx.patchState({
                            eventDetail: initialStateModel.eventDetail
                        });
                        throw new Error('Nepodařilo se nalézt detail akce');
                    }
                }),
                catchError(e => {
                    ctx.patchState({
                        eventDetail: initialStateModel.eventDetail
                    });

                    throw e;
                })
            );
        }
    }

    @Action(LoadCampUnits)
    loadCampUnits(ctx: StateContext<CampEventDetailStateModel>, action: LoadCampUnits) {
        const tk = AppSettings.getString(USER_TOKEN);
        const reqs = action.ids.map(id => this.webApiService.call(
            new UnitDetail(APP_ID, tk, parseInt(id, 10)),
            () => new UnitDetailOutput(),
            wsOrganizationUnit
        ));

        return zip(...reqs).pipe(
            tap((response: UnitDetailOutput[][]) => {
                const campUnits = response.reduce((acc, curr) => acc.concat(curr), [])
                ctx.patchState({
                    campUnits
                });

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

                throw e;
            })
        );

    }

    @Action(LoadCampEventLeaders)
    loadEventLeaders(ctx: StateContext<CampEventDetailStateModel>, action: LoadCampEventLeaders) {
        if (action.id) {
            return this.webApiService.call(
                new EventFunctionAllCamp(AppSettings.getString(USER_TOKEN), action.id),
                () => new CampEventFunctionAllOutput(),
                wsEvents
            ).pipe(
                tap((response: CampEventFunctionAllOutput[]) => {
                    ctx.patchState({
                        leaderList: response
                    });

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

                    throw e;
                })
            );
        }
    }

    @Action(LoadCampEventParticipants)
    loadEventParticipants(ctx: StateContext<CampEventDetailStateModel>, action: LoadCampEventParticipants) {
        if (action.id) {
            return this.webApiService.call(
                new ParticipantCampAll(AppSettings.getString(USER_TOKEN), action.id),
                () => new CampEventParticipantAllOutput(),
                wsEvents
            ).pipe(
                tap((response: CampEventParticipantAllOutput[]) => {
                    ctx.patchState({
                        participants: response
                    });

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

                    throw e;
                })
            );
        }
    }

    @Action(CampEventUpdateParticipantList)
    updateEventParticipants(ctx: StateContext<CampEventDetailStateModel>, action: CampEventUpdateParticipantList) {
        if (action.payload) {
            const { ID, Days, Real, Estimate, Note, } = action.payload
            const state = ctx.getState().participants
            ctx.patchState({ participants: state.map(p => p.ID !== ID ? p : { ...p, Days, Real, Estimate, Note }) })
        }
    }

    @Action(CampEventRemoveParticipant)
    removeParticipant(ctx: StateContext<CampEventDetailStateModel>, { participantId }: CampEventRemoveParticipant) {
        const tk = AppSettings.getString(USER_TOKEN)
        if (participantId) {
            const event = new ParticipantCampDelete(
                AppSettings.getString(USER_TOKEN), participantId
            );
            return this.webApiService.call(event,
                () => ({}),
                wsEvents
            ).pipe(
                tap(() => {
                    ctx.patchState({ participants: ctx.getState().participants.filter(p => p.ID !== participantId) })
                    feedbackMessage(FeedbackType.Success, 'Účastník smazan.', `Id: ${participantId}`)
                }),
                errorFeedbackOperator('CampEventRemoveParticipant')
            );
        }
    }

    @Action(LoadCampEventStatisticDetail)
    loadEventStatisticDetail(ctx: StateContext<CampEventDetailStateModel>, action: LoadCampEventStatisticDetail) {
        const tk = AppSettings.getString(USER_TOKEN);
        if (action.id) {
            const reqs = [
                new EventCampStatisticDetail(tk, action.id, true),
                new EventCampStatisticDetail(tk, action.id, false)
            ].map(req => this.webApiService.call(
                req,
                () => new EventCampStatisticDetailOutput(),
                wsEvents
            ))
            return zip(...reqs)
                .pipe(tap(([real, estimate]: EventCampStatisticDetailOutput[][]) => {
                    if (real && estimate && real.length === 1 && estimate.length === 1) {
                        ctx.patchState({
                            statisticDetail: { real: real[0], estimate: estimate[0] }
                        });
                    } else {
                        ctx.patchState({
                            statisticDetail: initialStateModel.statisticDetail
                        });
                    }

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

                        throw e;
                    })
                );
        }
    }
    @Action(CampEventUpdateFunctions)
    updateFunctions(ctx: StateContext<CampEventDetailStateModel>,
        { eventId, members }: CampEventUpdateFunctions) {
        const input = new EventCampUpdateFunction(
            AppSettings.getString(USER_TOKEN),
            eventId,
        )
        members.forEach(m => {
            const roleName = CampEventFunctionNames[m.EventFunctionType]
            input['ID_Person' + roleName] = m.ID_Person || undefined;
            input[roleName + 'Note'] = m.Note || undefined;
            // if (['Leader', 'Assistant'].indexOf(roleName) > -1) {
            //     input[roleName + 'HealthQualification'] = m.HealthQualification 
            //     input[roleName + 'HealthQualificationDate'] = m.HealthQualificationDate || undefined
            // }

        })
        if (eventId) {
            return this.webApiService.call(input,
                () => new CampEventUpdateFunctionOutput(),
                wsEvents
            ).pipe(
                tap((response: CampEventUpdateFunctionOutput[]) => {
                    feedbackMessage(FeedbackType.Success, "Vedení táboru", "Vedení táboru bylo upraveno")
                }),
                catchError(e => {
                    const actionName = 'CampEventUpdateFunctions'
                    if (e.error.indexOf('EnterLeaderNote') > -1)
                        errorFeedback(actionName + 'EnterLeaderNote');
                    else if (e.error.indexOf('EnterAssistantNote') > -1)
                        errorFeedback(actionName + 'EnterAssistantNote');
                    else if (e.error.indexOf("EnterMedicNote") > -1)
                        errorFeedback(actionName + 'EnterMedicNote');
                    else if (e.error.indexOf("LeaderMustBeAdult") > -1)
                        errorFeedback(actionName + 'LeaderMustBeAdult');
                    else if (e.error.includes('PermissionDenied'))
                        errorFeedback('CampEventUpdateFunctionsPermissionDenied');
                    else
                        errorFeedback('CampEventUpdateFunctionsPermissionDenied');
                    throw e;
                })
            );

        }
    }
}
