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

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 { CampPlaceAll, CampTypeAll, CampTypeOutput, EventCampInsert, EventCampUpdate, UnitAllCamp, UnitCampOutput, UnitOutput } from '../../entities/camp-event-new.types';
import { UnitAll } from '../../entities/gen-event-new.types';
import { SearchUnits } from '../gen/gen-event-new.actions';
import { errorFeedback, errorFeedbackOperator } from '../gen/gen-event-new.state';
import { LoadCampPlaceAll, LoadCampTypes, LoadUnitAllCamp, NewCampEvent, UpdateCampEvent } from './camp-event-new.actions';
import { CampPlaceOutput } from './../../entities/camp-event-new.types';
import { CampEventDetailOutput } from '../../entities/camp-event-detail.types';


export interface CampEventNewStateModel {
    eventDetail: CampEventDetailOutput;
    units: UnitOutput[];
    types: CampTypeOutput[];
    newEventId: number;
    places: CampPlaceOutput[];
    campUnits: UnitCampOutput[];
}

const initialStateModel: CampEventNewStateModel = {
    eventDetail: null,
    units: [],
    types: [],
    newEventId: null,
    places: [],
    campUnits: [],
};

@State<CampEventNewStateModel>({
    name: 'CampEventNew',
    defaults: initialStateModel
})
export class CampEventNewState {
    @Selector()
    static getEventDetail(state: CampEventNewStateModel) {
        return state.eventDetail;
    }
    @Selector()
    static getUnits(state: CampEventNewStateModel) {
        return state.units;
    }
    @Selector()
    static getCampUnits(state: CampEventNewStateModel) {
        return state.campUnits;
    }
    @Selector()
    static getNewEventId(state: CampEventNewStateModel) {
        return state.newEventId;
    }
    @Selector()
    static getTypes(state: CampEventNewStateModel) {
        return state.types;
    }
    @Selector()
    static getPlaces(state: CampEventNewStateModel) {
        return state.places;
    }

    constructor(
        private webApiService: WebApiService,

    ) {
    }


    @Action(NewCampEvent)
    newCampEvent(ctx: StateContext<CampEventNewStateModel>, action: NewCampEvent) {
        const {
            name, startDate, endDate, gpsLatitude, gpsLongitude,
            typeIds, region, location, unitId, note,
            mobile, postCode, isFloodArea, campPlaceId, subUnitIds
        } = action.payload;
        const regionId = parseInt(region)

        const event = new EventCampInsert(0,
            AppSettings.getString(USER_TOKEN),
            name, unitId, region, regionId || undefined,
            startDate.toISOString(), endDate.toISOString(),
            parseFloat(gpsLatitude) || null, parseFloat(gpsLongitude) || null,
            location || undefined, note, mobile,
            postCode || '', isFloodArea, campPlaceId || undefined, subUnitIds, typeIds
        );
        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, 'Tábor vytvořen', 'Tábor úspěšně vytvořen.')
                    ctx.patchState({ newEventId: res[0].ID })
                } else {
                    ctx.patchState({ newEventId: initialStateModel.newEventId })
                    errorFeedback('NewCampEvent');
                }
            }),
            errorFeedbackOperator('NewCampEventInvalid')
        );

    }

    @Action(UpdateCampEvent)
    updateCampEvent(ctx: StateContext<CampEventNewStateModel>, action: UpdateCampEvent) {
        const {
            name, startDate, endDate, gpsLatitude, gpsLongitude,
            typeIds, region, location, unitId, note,
            mobile, postCode, isFloodArea, campPlaceId, subUnitIds,
        } = action.payload;

        const regionId = parseInt(region);

        const event = new EventCampUpdate(action.eventId,
            AppSettings.getString(USER_TOKEN),
            name, unitId, region, regionId || undefined,
            startDate.toISOString(), endDate.toISOString(),
            parseFloat(gpsLatitude) || null, parseFloat(gpsLongitude) || null,
            location || undefined, note, mobile,
            postCode || '', isFloodArea, campPlaceId || undefined, subUnitIds, typeIds
        );
        return this.webApiService.call(event,
            () => ({ ID: 0 }),
            wsEvents
        ).pipe(
            tap(() => {
                feedbackMessage(FeedbackType.Success, 'Tábor upraven', 'Tábor úspěšně upraven.');
            }),
            errorFeedbackOperator('UpdateCampEventInvalid')
        );

    }

    @Action(SearchUnits)
    loadUnits(ctx: StateContext<CampEventNewStateModel>,
        { options, typeId }: SearchUnits) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new UnitAll(tk);
        input.ID_UnitType = typeId;
        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;
            })
        );
    }

    @Action(LoadCampTypes)
    loadCampTypes(ctx: StateContext<CampEventNewStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new CampTypeAll(tk);
        return this.webApiService.call(input,
            () => new CampTypeOutput(),
            wsEvents
        ).pipe(
            tap((response: CampTypeOutput[]) => {
                ctx.patchState({
                    types: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    types: initialStateModel.types
                });

                throw e;
            })
        );
    }
    @Action(LoadCampPlaceAll)
    loadCampPlaces(ctx: StateContext<CampEventNewStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new CampPlaceAll(tk);
        return this.webApiService.call(input,
            () => new CampPlaceOutput(),
            wsEvents
        ).pipe(
            tap((response: CampPlaceOutput[]) => {
                ctx.patchState({
                    places: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    places: initialStateModel.places
                });

                throw e;
            })
        );
    }
    @Action(LoadUnitAllCamp)
    loadUnitsForCamp(ctx: StateContext<CampEventNewStateModel>) {
        const tk = AppSettings.getString(USER_TOKEN)
        const input = new UnitAllCamp(tk);
        return this.webApiService.call(input,
            () => new UnitCampOutput(),
            wsOrganizationUnit
        ).pipe(
            tap((response: UnitCampOutput[]) => {
                ctx.patchState({
                    campUnits: response
                });
            }),
            catchError(e => {
                ctx.patchState({
                    campUnits: initialStateModel.campUnits
                });

                throw e;
            })
        );
    }

}