import { ActionReducer, ReducerTypes, createReducer, on } from '@ngrx/store';
import {
  createEmptyStateResource,
  createErrorStateResource,
  createStateResource,
} from '../resource/resource.util';
import {
  ApiSingleResourceActions,
  LoadResourceFailureProps,
  LoadResourceSuccessProps,
  SingleResourceLoadActions,
} from './actions';
import {
  ApiSingleResourceState,
  SingleResourceState,
  initialApiResourceState,
  initialResourceState,
} from './state.model';

export class SingleResourceReducer {
  public reducer: ActionReducer<SingleResourceState>;

  protected loadActionReducerType: ReducerTypes<SingleResourceState, any>;
  protected loadSuccessActionReducerType: ReducerTypes<SingleResourceState, any>;
  protected loadFailureActionReducerType: ReducerTypes<SingleResourceState, any>;
  protected clearActionReducerType: ReducerTypes<SingleResourceState, any>;
  protected reloadActionReducerType: ReducerTypes<SingleResourceState, any>;

  constructor(protected actions: SingleResourceLoadActions) {
    this.initReducerTypes();
    this.initReducer();
  }

  initReducerTypes() {
    this.loadActionReducerType = this.createLoadActionReducerType();
    this.loadSuccessActionReducerType = this.createLoadSuccessActionReducerType();
    this.loadFailureActionReducerType = this.createLoadFailureActionReducerType();
    this.clearActionReducerType = this.createClearActionReducerType();
    this.reloadActionReducerType = this.createReloadActionReducerType();
  }

  protected initReducer(): void {
    this.reducer = createReducer(
      initialResourceState,
      this.loadActionReducerType,
      this.loadSuccessActionReducerType,
      this.loadFailureActionReducerType,
      this.clearActionReducerType,
      this.reloadActionReducerType,
    );
  }

  createLoadActionReducerType(): ReducerTypes<SingleResourceState, any> {
    return on(this.actions.loadAction, (state: SingleResourceState): SingleResourceState => {
      return {
        ...state,
        resource: { ...state.resource, loading: true },
      };
    });
  }

  createLoadSuccessActionReducerType(): ReducerTypes<SingleResourceState, any> {
    return on(
      this.actions.loadSuccessAction,
      (state: SingleResourceState, props: LoadResourceSuccessProps): SingleResourceState => {
        return {
          ...state,
          resource: createStateResource(props.resource),
        };
      },
    );
  }

  createLoadFailureActionReducerType(): ReducerTypes<SingleResourceState, any> {
    return on(
      this.actions.loadFailureAction,
      (state: SingleResourceState, props: LoadResourceFailureProps): SingleResourceState => ({
        ...state,
        resource: createErrorStateResource(props.error),
      }),
    );
  }

  createClearActionReducerType(): ReducerTypes<SingleResourceState, any> {
    return on(
      this.actions.clearAction,
      (state: SingleResourceState): SingleResourceState => ({
        ...state,
        resource: createEmptyStateResource(),
      }),
    );
  }

  createReloadActionReducerType(): ReducerTypes<SingleResourceState, any> {
    return on(
      this.actions.reloadAction,
      (state: SingleResourceState): SingleResourceState => ({
        ...state,
        resource: { ...state.resource, reload: true },
      }),
    );
  }
}

export class ApiSingleResourceReducer extends SingleResourceReducer {
  public reducer: ActionReducer<ApiSingleResourceState>;

  constructor(protected actions: ApiSingleResourceActions) {
    super(actions);
  }

  initReducer(): void {
    this.reducer = createReducer(
      initialApiResourceState,
      this.loadActionReducerType,
      this.loadSuccessActionReducerType,
      this.loadFailureActionReducerType,
      this.clearActionReducerType,
      this.reloadActionReducerType,
      on(this.actions.saveAction, (state: ApiSingleResourceState): ApiSingleResourceState => {
        return {
          ...state,
          saveResource: createEmptyStateResource(true),
        };
      }),
      on(
        this.actions.saveSuccessAction,
        (
          state: ApiSingleResourceState,
          props: LoadResourceSuccessProps,
        ): ApiSingleResourceState => {
          return {
            ...state,
            saveResource: createStateResource(props.resource),
          };
        },
      ),
      on(
        this.actions.saveFailureAction,
        (
          state: ApiSingleResourceState,
          props: LoadResourceFailureProps,
        ): ApiSingleResourceState => {
          return {
            ...state,
            saveResource: createErrorStateResource(props.error),
          };
        },
      ),
    );
  }
}