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

import { LoadGenEventStates } from '~/pages/event/state-mgmt/gen/gen-event-search.actions';
import { GenEventOutput, GenEventType, GenEventState, GenEventScope, EventGeneralAll, EventGeneralTypeAll, EventGeneralStateAll, EventGeneralScopeAll } from '../../entities/gen-event-search.types';
import { FeedbackType } from 'nativescript-feedback';
import { feedbackMessage } from '~/pages/material/utils/feedback-messages';
import { EventGeneralDelete } from '../../entities/gen-event-new.types';
import { DeleteGenEvent } from './gen-event-new.actions';
import { errorFeedbackOperator } from './gen-event-new.state';
import { GenEventSortKey, SortDirection, SortParams } from '../../types/EventSorting';
import { ScheduleType, EventRel } from '../../types/GenEventSearch';


export interface GenEventSearchListStateModel {
    sortParams: SortParams;
    events: GenEventOutput[];
    eventTypes: GenEventType[];
    eventStates: GenEventState[];
    eventScopes: GenEventScope[];
    searchParams: GenEventSearch;
}
export interface GenEventSearch {
    year: string;
    type: string;
    state: string;
    scope: string;
    schedule: string;
    relation: string;
}

const initialStateModel: GenEventSearchListStateModel = {
    events: [],
    eventTypes: [],
    eventScopes: [],
    eventStates: [],
    searchParams: {
        year: (new Date()).getFullYear().toString(),
        type: null,
        scope: null,
        state: null,
        schedule: 'year',
        relation: EventRel.ME_AND_MY_UNIT
    },
    sortParams: {
        sortByKey: GenEventSortKey.NAME,
        sortDirection: SortDirection.ASC,
    },
};


@State<GenEventSearchListStateModel>({
    name: 'GenEventSearchList',
    defaults: initialStateModel
})

export class GenEventSearchListState {
    constructor(
        private webApiService: WebApiService
    ) {
    }
    @Selector()
    static getEvents(state: GenEventSearchListStateModel) {
        return state.events;
    }
    @Selector()
    static getEventTypes(state: GenEventSearchListStateModel) {
        return state.eventTypes;
    }
    @Selector()
    static getEventScopes(state: GenEventSearchListStateModel) {
        return state.eventScopes;
    }
    @Selector()
    static getEventStates(state: GenEventSearchListStateModel) {
        return state.eventStates;
    }
    @Selector()
    static getSearchParams(state: GenEventSearchListStateModel) {
        return state.searchParams;
    }
    @Selector()
    static getSortParams(state: GenEventSearchListStateModel) {
        return state.sortParams;
    }

    @Selector()
    static isSearchSortDirty(state: GenEventSearchListStateModel) {
        const [a, b] = [JSON.stringify(initialStateModel.searchParams), JSON.stringify(state.searchParams)]
        const [c, d] = [JSON.stringify(initialStateModel.sortParams), JSON.stringify(state.sortParams)]
        return a !== b || c !== d;
    }

    @Action(LoadGenEvents)
    loadEvents(ctx: StateContext<GenEventSearchListStateModel>) {
        const { year, type, scope, state, schedule, relation } = ctx.getState().searchParams;
        const tk = AppSettings.getString(USER_TOKEN)
        return this.webApiService.call(
            new EventGeneralAll(tk,
                schedule === ScheduleType.YEAR ? parseInt(year, 10) : null,
                type ? parseInt(type, 10) : null,
                state,
                scope ? parseInt(scope, 10) : null,
                schedule === ScheduleType.FUTURE ? true :
                    schedule === ScheduleType.PAST ? false : null,
                relation === EventRel.ME_AND_MY_UNIT || null,
                relation === EventRel.UNIT_PLACE || null,
                relation === EventRel.ALL_UNIT_PLACE || null
            ),
            () => new GenEventOutput(),
            wsEvents
        ).pipe(
            tap((response: GenEventOutput[]) => {
                ctx.patchState({
                    events: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    events: initialStateModel.events
                });

                throw e;
            })
        );
    }

    @Action(DeleteGenEvent)
    deleteGenEvent(ctx: StateContext<GenEventSearchListStateModel>, action: DeleteGenEvent) {

        if (action.id) {
            const event = new EventGeneralDelete(
                AppSettings.getString(USER_TOKEN), action.id
            );
            return this.webApiService.call(event,
                () => ({}),
                wsEvents
            ).pipe(
                tap(() => {
                    feedbackMessage(FeedbackType.Success, 'Akce smazana.', `Id: ${action.id}`)
                    const filteredList = ctx.getState().events.filter(i => i.ID != action.id);
                    ctx.patchState({ events: filteredList })
                }),
                errorFeedbackOperator('NewGenEventInvalid')
            );
        }
    }

    @Action(SetGenEventSortParams)
    setSortParams(ctx: StateContext<GenEventSearchListStateModel>, { payload }: SetGenEventSortParams) {
        ctx.patchState({
            sortParams: payload || { ...initialStateModel.sortParams },
        })
    }
    @Action(SetGenEventSearchParams)
    setSearchParams(ctx: StateContext<GenEventSearchListStateModel>, { payload }: SetGenEventSearchParams) {
        ctx.patchState({
            searchParams: payload || { ...initialStateModel.searchParams }
        })
    }
    @Action(LoadGenEventTypes)
    loadTypes(ctx: StateContext<GenEventSearchListStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        return this.webApiService.call(
            new EventGeneralTypeAll(tk),
            () => new GenEventType(),
            wsEvents
        ).pipe(
            tap((response: GenEventType[]) => {
                ctx.patchState({
                    eventTypes: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    eventTypes: initialStateModel.eventTypes
                });

                throw e;
            })
        );
    }

    @Action(LoadGenEventStates)
    loadStates(ctx: StateContext<GenEventSearchListStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        return this.webApiService.call(
            new EventGeneralStateAll(tk),
            () => new GenEventState(),
            wsEvents
        ).pipe(
            tap((response: GenEventState[]) => {
                ctx.patchState({
                    eventStates: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    eventStates: initialStateModel.eventStates
                });

                throw e;
            })
        );
    }

    @Action(LoadGenEventStates)
    loadScopes(ctx: StateContext<GenEventSearchListStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        return this.webApiService.call(
            new EventGeneralScopeAll(tk),
            () => new GenEventScope(),
            wsEvents
        ).pipe(
            tap((response: GenEventScope[]) => {
                ctx.patchState({
                    eventScopes: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    eventScopes: initialStateModel.eventScopes
                });

                throw e;
            })
        );
    }
}
