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

import { wsEvents } from '~/constants/api.constants';
import { USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { GenEventRemoveParticipantFromList, GenEventUpdateState, GenEventUpdateParticipantList, LoadGenEventDetail, LoadGenEventLeaders, LoadGenEventParticipants, LoadGenEventStatisticAll, SetGenEventParticipantSortParams, GenEventUpdateReport, GenEventUpdateFunctions } from './gen-event-detail.actions';
import { EventFunctionAllGeneral, EventGeneralDetail, EventGeneralUpdateClose, EventGeneralUpdateFunction, EventGeneralUpdateOpen, EventStatisticAllEventGeneral, GenEventDetailOutput, GenEventFunctionAllOutput, GenEventParticipantAllOutput, GenEventStatisticOutput, ParticipantGeneralAll } from '../../entities/gen-event-detail.types';
import { SortParams, SortDirection, GenParticipantSortKey } from '~/pages/event/types/EventSorting';
import { errorFeedback, errorFeedbackOperator } from './gen-event-new.state';
import { feedbackMessage } from './../../../material/utils/feedback-messages';
import { FeedbackType } from 'nativescript-feedback';
import { EventGeneralUpdateReport, GenEventUpdateFunctionOutput } from './../../entities/gen-event-detail.types';

export interface GenEventDetailStateModel {
    genParticipantsSortParams: SortParams;
    eventDetail: GenEventDetailOutput;
    eventLeaderDetail: GenEventFunctionAllOutput[];
    participants: GenEventParticipantAllOutput[];
    participStats: GenEventStatisticOutput[];
}
export enum GenEventStateEnum {
    DRAFT = "draft",
    CLOSED = "closed",
    OPEN = "open",
}
const GenEventFunctionNames = {
    "Vedoucí akce": "Leader",
    "Zastupce vedoucího": "Assistant",
    "Hospodář": "Economist",
    "Zdravotník": "Medic",
}

const initialStateModel: GenEventDetailStateModel = {
    eventDetail: null,
    eventLeaderDetail: [],
    participants: [],
    participStats: [],
    genParticipantsSortParams: { sortByKey: GenParticipantSortKey.NAME, sortDirection: SortDirection.ASC }
};

@State<GenEventDetailStateModel>({
    name: 'genEventDetail',
    defaults: initialStateModel
})
export class GenEventDetailState {

    @Selector()
    static getGenParticipantsSortParams(state: GenEventDetailStateModel) {
        return state.genParticipantsSortParams;
    }
    @Selector()
    static getEventDetail(state: GenEventDetailStateModel) {
        return state.eventDetail;
    }
    @Selector()
    static getEventLeaderDetail(state: GenEventDetailStateModel) {
        return state.eventLeaderDetail
    }
    @Selector()
    static getParticipants(state: GenEventDetailStateModel) {
        return state.participants
    }
    @Selector()
    static getParticipantStats(state: GenEventDetailStateModel) {
        return state.participStats
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    @Action(SetGenEventParticipantSortParams)
    setSortParams(ctx: StateContext<GenEventDetailStateModel>,
        { payload }: SetGenEventParticipantSortParams) {
        ctx.patchState({
            genParticipantsSortParams: payload || { ...initialStateModel.genParticipantsSortParams }
        })
    }

    @Action(LoadGenEventDetail)
    loadEventDetail(ctx: StateContext<GenEventDetailStateModel>, action: LoadGenEventDetail) {
        if (action.id) {
            return this.webApiService.call(
                new EventGeneralDetail(AppSettings.getString(USER_TOKEN), action.id),
                () => new GenEventDetailOutput(),
                wsEvents
            ).pipe(
                tap((response: GenEventDetailOutput[]) => {
                    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(LoadGenEventLeaders)
    loadEventLeaders(ctx: StateContext<GenEventDetailStateModel>, action: LoadGenEventLeaders) {
        if (action.id) {
            return this.webApiService.call(
                new EventFunctionAllGeneral(AppSettings.getString(USER_TOKEN), action.id),
                () => new GenEventFunctionAllOutput(),
                wsEvents
            ).pipe(
                tap((response: GenEventFunctionAllOutput[]) => {
                    ctx.patchState({
                        eventLeaderDetail: response
                    });

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

                    throw e;
                })
            );
        }
    }

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

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

                    throw e;
                })
            );
        }
    }
    @Action(GenEventUpdateParticipantList)
    updateEventParticipant(ctx: StateContext<GenEventDetailStateModel>, action: GenEventUpdateParticipantList) {
        if (action.payload) {
            const { ID, Days, Note, } = action.payload
            const state = ctx.getState().participants
            ctx.patchState({ participants: state.map(p => p.ID !== ID ? p : { ...p, Days, Note }) })
        }
    }

    @Action(GenEventRemoveParticipantFromList)
    removeParticipant(ctx: StateContext<GenEventDetailStateModel>, { participantId }: GenEventRemoveParticipantFromList) {
        if (participantId) {
            ctx.patchState({ participants: ctx.getState().participants.filter(p => p.ID !== participantId) })
        }
    }

    @Action(LoadGenEventStatisticAll)
    loadGenEventStatisticAll(ctx: StateContext<GenEventDetailStateModel>,
        action: LoadGenEventStatisticAll) {
        if (action.id) {
            return this.webApiService.call(
                new EventStatisticAllEventGeneral(AppSettings.getString(USER_TOKEN), action.id),
                () => new GenEventStatisticOutput(),
                wsEvents
            ).pipe(
                tap((response: GenEventStatisticOutput[]) => {
                    ctx.patchState({
                        participStats: response
                    });

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

                    throw e;
                })
            );
        }
    }

    @Action(GenEventUpdateState)
    updateGenEventState(ctx: StateContext<GenEventDetailStateModel>,
        action: GenEventUpdateState) {
        if (action.id) {

            if (action.currentStateId === GenEventStateEnum.CLOSED) {
                return this.webApiService.call(
                    new EventGeneralUpdateOpen(AppSettings.getString(USER_TOKEN), action.id),
                    () => new GenEventDetailOutput(),
                    wsEvents
                ).pipe(
                    tap((response: GenEventDetailOutput[]) => {
                        feedbackMessage(FeedbackType.Success, "Akce otevřena", "Akce otevřena")
                        ctx.dispatch(new LoadGenEventDetail(action.id));
                    }),
                    errorFeedbackOperator('GenEventUpdateClose')
                );
            } else {
                return this.webApiService.call(
                    new EventGeneralUpdateClose(AppSettings.getString(USER_TOKEN), action.id),
                    () => new GenEventDetailOutput(),
                    wsEvents
                ).pipe(
                    tap((response: GenEventDetailOutput[]) => {
                        feedbackMessage(FeedbackType.Success, "Akce uzavřena", "Akce uzavřena")
                        ctx.dispatch(new LoadGenEventDetail(action.id));
                    }),
                    catchError(e => {
                        if (e.error.includes('EnterLeader'))
                            errorFeedback('GenEventUpdateStateEnterLeader');
                        else if (e.error.includes('PermissionDenied'))
                            errorFeedback('GenEventUpdateStatePermissionDenied');
                        else
                            errorFeedback('GenEventUpdateState');
                        throw e;
                    })
                );
            }
        }
    }

    @Action(GenEventUpdateReport)
    updateGenEventReport(ctx: StateContext<GenEventDetailStateModel>,
        { id, report }: GenEventUpdateReport) {

        if (id) {
            return this.webApiService.call(
                new EventGeneralUpdateReport(
                    AppSettings.getString(USER_TOKEN),
                    id, report.target, report.program
                ),
                () => new GenEventDetailOutput(),
                wsEvents
            ).pipe(
                tap((response: GenEventDetailOutput[]) => {
                    feedbackMessage(FeedbackType.Success, "Zpráva akce upravena", "Zpráva akce upravena")
                    ctx.dispatch(new LoadGenEventDetail(id));
                }),
                errorFeedbackOperator('GenEventUpdateClose')
            );

        }
    }

    @Action(GenEventUpdateFunctions)
    updateFunctions(ctx: StateContext<GenEventDetailStateModel>,
        { eventId, members }: GenEventUpdateFunctions) {
        const input = new EventGeneralUpdateFunction(
            AppSettings.getString(USER_TOKEN),
            eventId,
        )
        members.forEach(m => {
            input['ID_Person' + GenEventFunctionNames[m.roleName]] = m.memberId || undefined;
            input[GenEventFunctionNames[m.roleName] + 'Note'] = m.note || undefined;
        })

        if (eventId) {
            return this.webApiService.call(input,
                () => new GenEventUpdateFunctionOutput(),
                wsEvents
            ).pipe(
                tap((response: GenEventUpdateFunctionOutput[]) => {
                    feedbackMessage(FeedbackType.Success, "Vedení obecné akce ", "Vedení obecné akce bylo upraveno")
                }),
                errorFeedbackOperator('GenEventUpdateFunctions')

            );

        }
    }
}
