import { createFeature, createReducer, on } from '@ngrx/store';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { Branch } from '../../models/auth.model';
import { PaginationMeta } from '../../models/api.model';
import { BranchesActions } from './branches.actions';

export interface BranchesState extends EntityState<Branch> {
  meta: PaginationMeta | null;
  loading: boolean;
  saving: boolean;
  error: string | null;
  loaded: boolean;
}

export const branchesAdapter: EntityAdapter<Branch> = createEntityAdapter<Branch>();

const initialState: BranchesState = branchesAdapter.getInitialState({
  meta: null,
  loading: false,
  saving: false,
  error: null,
  loaded: false,
});

export const branchesFeature = createFeature({
  name: 'branches',
  reducer: createReducer(
    initialState,
    // Load
    on(BranchesActions.loadBranches, (state, action) =>
      state.loaded && !action.forceReload ? state : {
        ...state,
        loading: true,
        error: null,
      }
    ),
    on(BranchesActions.loadBranchesSuccess, (state, { branches, meta }) =>
      branchesAdapter.setAll(branches, { ...state, meta, loading: false, loaded: true })
    ),
    on(BranchesActions.loadBranchesFailure, (state, { error }) => ({
      ...state,
      loading: false,
      error,
    })),
    // Create
    on(BranchesActions.createBranch, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(BranchesActions.createBranchSuccess, (state, { branch }) =>
      branchesAdapter.addOne(branch, { ...state, saving: false })
    ),
    on(BranchesActions.createBranchFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    // Update
    on(BranchesActions.updateBranch, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(BranchesActions.updateBranchSuccess, (state, { branch }) =>
      branchesAdapter.upsertOne(branch, { ...state, saving: false })
    ),
    on(BranchesActions.updateBranchFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    // Delete
    on(BranchesActions.deleteBranch, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(BranchesActions.deleteBranchSuccess, (state, { id }) =>
      branchesAdapter.removeOne(id, { ...state, saving: false })
    ),
    on(BranchesActions.deleteBranchFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    // Clear Error
    on(BranchesActions.clearBranchesError, (state) => ({
      ...state,
      error: null,
    }))
  ),
});

const { selectAll, selectEntities, selectTotal } = branchesAdapter.getSelectors(branchesFeature.selectBranchesState);

export const selectAllBranches = selectAll;
export const selectBranchEntities = selectEntities;
export const selectBranchesTotal = selectTotal;
export const selectBranchesMeta = branchesFeature.selectMeta;
export const selectBranchesLoading = branchesFeature.selectLoading;
export const selectBranchesSaving = branchesFeature.selectSaving;
export const selectBranchesError = branchesFeature.selectError;
export const selectBranchesLoaded = branchesFeature.selectLoaded;
