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

import { erroredActions } from '~/constants/action-errored-catch.constants';
import { wsEvents, wsOrganizationUnit } from '~/constants/api.constants';
import { USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { feedbackMessage } from '~/pages/material/utils/feedback-messages';
import { GenEventDetailOutput } from '../../entities/gen-event-detail.types';
import { EventGeneralInsert, EventGeneralUpdate, RegionAll, RegionOutput, UnitAll, UnitOutput } from '~/pages/event/entities/gen-event-new.types';
import { LoadRegions, SearchUnits, NewGenEvent, UpdateGenEvent } from './gen-event-new.actions';


export interface GenEventNewStateModel {
    eventDetail: GenEventDetailOutput;
    regions: RegionOutput[];
    units: UnitOutput[];
    newEventId: number;
}

const initialStateModel: GenEventNewStateModel = {
    eventDetail: null,
    regions: [],
    units: [],
    newEventId: null,
};

@State<GenEventNewStateModel>({
    name: 'genEventNew',
    defaults: initialStateModel
})
export class GenEventNewState {
    @Selector()
    static getRegions(state: GenEventNewStateModel) {
        return state.regions
    }
    @Selector()
    static getEventDetail(state: GenEventNewStateModel) {
        return state.eventDetail;
    }
    @Selector()
    static getUnits(state: GenEventNewStateModel) {
        return state.units;
    }
    @Selector()
    static getNewEventId(state: GenEventNewStateModel) {
        return state.newEventId;
    }

    constructor(
        private webApiService: WebApiService,

    ) {
    }


    @Action(NewGenEvent)
    newGenEvent(ctx: StateContext<GenEventNewStateModel>, action: NewGenEvent) {
        const {
            type, scope, name, startDate, endDate,
            endTime, startTime, unitId, note,
            gpsLatitude, gpsLongitude, street,
            postCode, region, state, city } = action.payload;
        if (startTime) {
            const [sHours, sMins] = startTime.split(':')
            startDate.setHours(parseInt(sHours, 10));
            startDate.setMinutes(parseInt(sMins, 10))
        }
        if (endTime) {
            const [eHours, eMins] = endTime.split(':')
            endDate.setHours(parseInt(eHours, 10));
            endDate.setMinutes(parseInt(eMins, 10))
        }
        const event = new EventGeneralInsert(
            AppSettings.getString(USER_TOKEN),
            name, startDate.toISOString(), endDate.toISOString(),
            unitId, note, type, scope,
            street, city, postCode, region, state,
            parseFloat(gpsLatitude) || null, parseFloat(gpsLongitude) || null
        );
        ctx.patchState({ newEventId: initialStateModel.newEventId })


        return this.webApiService.call(event,
            () => ({ ID: 0 }),
            wsEvents
        ).pipe(
            tap((res: { ID: 0 }[]) => {
                if (res.length === 1) {
                    feedbackMessage(FeedbackType.Success, 'Obecná akce', 'Obecná akce úspěšně vytvořena')
                    ctx.patchState({ newEventId: res[0].ID })
                } else {
                    ctx.patchState({ newEventId: initialStateModel.newEventId })
                    errorFeedback('NewGenEvent');
                }
            }),
            errorFeedbackOperator('NewGenEventInvalid')
        );

    }

    @Action(UpdateGenEvent)
    updateGenEvent(ctx: StateContext<GenEventNewStateModel>, action: UpdateGenEvent) {
        const {
            type, scope, name, startDate, endDate,
            endTime, startTime, unitId, note,
            gpsLatitude, gpsLongitude, street,
            postCode, region, state, city } = action.payload;
        const timezoneOffset = startDate.getTimezoneOffset(); //time offset because server time is not GMT

        if (startTime) {
            const [sHours, sMins] = startTime.split(':')
            startDate.setHours(parseInt(sHours, 10));
            startDate.setMinutes(parseInt(sMins, 10) - timezoneOffset)
        }
        if (endTime) {
            const [eHours, eMins] = endTime.split(':')
            endDate.setHours(parseInt(eHours, 10));
            endDate.setMinutes(parseInt(eMins, 10) - timezoneOffset)
        }
        const [s, e] = [startDate.toLocaleString(), endDate.toLocaleString()]
        const event = new EventGeneralUpdate(action.eventId,
            AppSettings.getString(USER_TOKEN),
            name, startDate.toISOString(), endDate.toISOString(),
            unitId, note, type, scope,
            street, city, postCode, region, state,
            parseFloat(gpsLatitude) || null, parseFloat(gpsLongitude) || null
        );
        return this.webApiService.call(event,
            () => ({}),
            wsEvents
        ).pipe(
            tap((res: any) => {
                feedbackMessage(FeedbackType.Success, 'Obecná akce', 'Obecná akce úspěšně upravena')
            }),
            errorFeedbackOperator('NewGenEventInvalid')
        );
    }

    @Action(LoadRegions)
    loadRegions(ctx: StateContext<GenEventNewStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        return this.webApiService.call(
            new RegionAll(tk),
            () => new RegionOutput(),
            wsEvents
        ).pipe(
            tap((response: RegionOutput[]) => {
                ctx.patchState({
                    regions: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    regions: initialStateModel.regions
                });

                throw e;
            })
        );
    }
    @Action(SearchUnits)
    loadUnits(ctx: StateContext<GenEventNewStateModel>, { options }: SearchUnits) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new UnitAll(tk);
        input[options.criteria] = options.text;
        return this.webApiService.call(input,
            () => new UnitOutput(),
            wsOrganizationUnit
        ).pipe(
            tap((response: UnitOutput[]) => {
                ctx.patchState({
                    units: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    units: initialStateModel.units
                });

                throw e;
            })
        );
    }

}
export function errorFeedbackOperator<T>(actionName: string): OperatorFunction<T, T> {
    return catchError(e => {
        if (e.error.includes('PermissionDenied'))
            errorFeedback(actionName + 'PermissionDenied');
        else
            errorFeedback(actionName);
        throw e;
    });
}

export function errorFeedback(actionName: string) {
    const selectedAction = erroredActions.find((eA) => eA.name === actionName);
    const fb = new Feedback()
    fb.show({
        title: 'ERROR',
        type: FeedbackType.Error,
        message: selectedAction ? selectedAction.message : 'Vyskytla se chyba při komunikaci se službou skautIS. Zkontrolujte připojení nebo to zkuste později.'
    });
}
