import { ApplicationSettings } from '@nativescript/core';
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { catchError, tap } from 'rxjs/operators';
import { APP_ID, wsOrganizationUnit } from '~/constants/api.constants';
import { USER_TOKEN } from '~/constants/login-constants';
import { WebApiService } from '~/core/services/web-api.service';
import { latinise } from '~/core/utils/functions';
import { PersonAll } from '~/pages/search-person/entities/input/personAll';
import { PersonAllCatalog } from '~/pages/search-person/entities/input/personAllCatalog';
import { MySearchPerson } from '~/pages/search-person/entities/my-search-person';
import { PersonAllCatalogOutput } from '~/pages/search-person/entities/output/personAllCatalogOutput';
import { PersonAllOutput } from '~/pages/search-person/entities/output/personAllOutput';
import { PersonSearch } from '~/pages/search-person/entities/person-search';
import {
    LoadCatalogPersons,
    LoadPersons,
    SetSearchPersonParams
} from '~/pages/search-person/state-mgmt/search-person-list.actions';

export interface SearchPersonListStateModel {
    loadingPersons: boolean;
    loadingCatalogPersons: boolean;
    persons: PersonAllOutput[];
    catalogPersons: PersonAllCatalogOutput[];
    searchPersonParams: PersonSearch;
}

const initialStateModel: SearchPersonListStateModel = {
    loadingPersons: false,
    loadingCatalogPersons: false,
    persons: [],
    catalogPersons: [],
    searchPersonParams: null
};

@State<SearchPersonListStateModel>({
    name: 'searchPersonList',
    defaults: initialStateModel
})

export class SearchPersonListState {

    @Selector()
    static getSearchPersons(state: SearchPersonListStateModel) {
        let searchPersons: MySearchPerson[];
        searchPersons = state.persons.map((value: PersonAllOutput) =>
            new MySearchPerson(value.ID, value.DisplayName, '', '', '', false)
        );

        state.catalogPersons.forEach((value: PersonAllCatalogOutput) => {
            if (!searchPersons.find(e => e.personId === value.ID)) {
                const mempershipSplit = value.Membership ? value.Membership.split('#') : [];
                searchPersons.push(
                    new MySearchPerson(
                        value.ID,
                        value.DisplayName,
                        value.Phone,
                        value.Email,
                        mempershipSplit.length > 0 ? mempershipSplit[0] : '',
                        true
                    )
                );
            }
        });

        return searchPersons;
    }

    @Selector()
    static getSearchPersonParams(state: SearchPersonListStateModel) {
        return state.searchPersonParams;
    }

    @Selector()
    static isLoading(state: SearchPersonListStateModel) {
        return state.loadingPersons || state.loadingCatalogPersons;
    }

    constructor(
        private webApiService: WebApiService
    ) {
    }

    @Action(LoadPersons)
    loadPersons(ctx: StateContext<SearchPersonListStateModel>, action: LoadPersons) {
        ctx.patchState({
            loadingPersons: true
        });

        const unitsSearchEnabled = ctx.getState().searchPersonParams.searchInUnits;

        if (unitsSearchEnabled) {
            return this.webApiService.call(
                new PersonAll(
                    APP_ID,
                    ApplicationSettings.getString(USER_TOKEN),
                    latinise(ctx.getState().searchPersonParams.name)
                ),
                () => new PersonAllOutput(),
                wsOrganizationUnit
            ).pipe(
                tap((response: PersonAllOutput[]) => {
                    ctx.patchState({
                        loadingPersons: false,
                        persons: response
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingPersons: false,
                        persons: initialStateModel.persons
                    });

                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingPersons: false,
                persons: initialStateModel.persons
            });
        }
    }

    @Action(LoadCatalogPersons)
    loadCatalogPersons(ctx: StateContext<SearchPersonListStateModel>, action: LoadCatalogPersons) {
        ctx.patchState({
            loadingCatalogPersons: true
        });

        const offer = ctx.getState().searchPersonParams.offer === 0 ? undefined : ctx.getState().searchPersonParams.offer;

        const addressBookSearchEnabled = ctx.getState().searchPersonParams.searchInAddressBook;

        if (addressBookSearchEnabled) {
            return this.webApiService.call(
                new PersonAllCatalog(APP_ID,
                    ApplicationSettings.getString(USER_TOKEN),
                    latinise(ctx.getState().searchPersonParams.name),
                    offer
                ),
                () => new PersonAllCatalogOutput(),
                wsOrganizationUnit
            ).pipe(
                tap((response: PersonAllCatalogOutput[]) => {
                    ctx.patchState({
                        loadingCatalogPersons: false,
                        catalogPersons: response
                    });
                }),
                catchError(e => {
                    ctx.patchState({
                        loadingCatalogPersons: false,
                        catalogPersons: initialStateModel.catalogPersons
                    });

                    throw e;
                })
            );
        } else {
            ctx.patchState({
                loadingCatalogPersons: false,
                catalogPersons: initialStateModel.catalogPersons
            });
        }
    }

    @Action(SetSearchPersonParams)
    setSearchPersonParams(ctx: StateContext<SearchPersonListStateModel>, action: SetSearchPersonParams) {
        ctx.patchState({
            searchPersonParams: action.payload
        });
    }

}
