import { InjectionToken } from '@angular/core';
import { ActionReducer, ActionReducerMap, MetaReducer, INIT, RuntimeChecks } from '@ngrx/store';
import * as fromRouter from '@ngrx/router-store';
import { storeFreeze } from 'ngrx-store-freeze';

import { reducers as coreReducers, CoreState, localStorageSync } from '@eui/core';
import { ElementStorageService } from '@csdr/core';

import { environment } from '../../environments/environment';

export interface AppState extends CoreState {
    router: fromRouter.RouterReducerState<any>;
}

// -----------------
// ------------ AOT
export const TOKEN = new InjectionToken<any>('AppReducers');

export function getReducers(): ActionReducerMap<AppState, any> {
    return {
        router: fromRouter.routerReducer,
        ...coreReducers,
    };
}

export const reducerProvider = [
    { provide: TOKEN, useFactory: getReducers },
];

// console.log all actions
export function logger(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
    return (state, action) => {
        const result = reducer(state, action);
        console.groupCollapsed(action.type);
        console.log('prev state', state);
        console.log('action', action);
        console.log('next state', result);
        console.groupEnd();

        return result;
    };
}

export function hydrationFactory(config: any, elementStorage: ElementStorageService): MetaReducer<AppState> {
    return (reducer: ActionReducer<AppState>): ActionReducer<any> => {
        return (state, action) => {
            const key = `NgRx store: ${config.global.elementName}`;
            if (action.type === INIT && elementStorage.hasData(key)) {
                const cachedState = elementStorage.getData(key);
                const nextStateFromCache = reducer(cachedState as AppState, action);
                elementStorage.setData(key, nextStateFromCache);
                return nextStateFromCache;
            }
            const nextState = reducer(state, action);
            elementStorage.setData(key, nextState);
            return nextState;
        };
    };
}

export function metaReducers(config: any, elementStorage: ElementStorageService): MetaReducer<AppState>[] {
    if (!environment.production) {
        return [logger, localStorageSync, storeFreeze, hydrationFactory(config, elementStorage)];
    }
    return [localStorageSync, hydrationFactory(config, elementStorage)];
}

export const runtimeChecks: RuntimeChecks = {
    strictStateSerializability: false,
    strictActionSerializability: false,
    strictStateImmutability: false,
    strictActionImmutability: false,
    strictActionWithinNgZone: false,
    strictActionTypeUniqueness: false,
};
