import { createFeature, createReducer, on } from '@ngrx/store';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { SalesDeliveryNote } from '../../../models/sales-delivery-note.model';
import { PaginationMeta } from '../../../models/api.model';
import { SalesDeliveryNotesActions } from './delivery-notes.actions';

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

export const salesDeliveryNotesAdapter: EntityAdapter<SalesDeliveryNote> =
  createEntityAdapter<SalesDeliveryNote>();

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

export const salesDeliveryNotesFeature = createFeature({
  name: 'salesDeliveryNotes',
  reducer: createReducer(
    initialState,
    on(SalesDeliveryNotesActions.loadDeliveryNotes, (state, action) =>
      state.loaded && !action.force ? state : { ...state, loading: true, error: null }
    ),
    on(SalesDeliveryNotesActions.loadDeliveryNotesSuccess, (state, { deliveryNotes, meta }) =>
      salesDeliveryNotesAdapter.setAll(deliveryNotes, {
        ...state,
        meta,
        loading: false,
        loaded: true,
      })
    ),
    on(SalesDeliveryNotesActions.loadDeliveryNotesFailure, (state, { error }) => ({
      ...state,
      loading: false,
      error,
    })),
    on(SalesDeliveryNotesActions.createDeliveryNote, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(SalesDeliveryNotesActions.createDeliveryNoteSuccess, (state, { deliveryNote }) =>
      salesDeliveryNotesAdapter.addOne(deliveryNote, { ...state, saving: false })
    ),
    on(SalesDeliveryNotesActions.createDeliveryNoteFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    on(SalesDeliveryNotesActions.updateDeliveryNote, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(SalesDeliveryNotesActions.updateDeliveryNoteSuccess, (state, { deliveryNote }) =>
      salesDeliveryNotesAdapter.upsertOne(deliveryNote, { ...state, saving: false })
    ),
    on(SalesDeliveryNotesActions.updateDeliveryNoteFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    on(SalesDeliveryNotesActions.deleteDeliveryNote, (state) => ({
      ...state,
      saving: true,
      error: null,
    })),
    on(SalesDeliveryNotesActions.deleteDeliveryNoteSuccess, (state, { id }) =>
      salesDeliveryNotesAdapter.removeOne(id, { ...state, saving: false })
    ),
    on(SalesDeliveryNotesActions.deleteDeliveryNoteFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    // Status change actions - set saving
    on(
      SalesDeliveryNotesActions.confirmDeliveryNote,
      SalesDeliveryNotesActions.shipDeliveryNote,
      SalesDeliveryNotesActions.deliverDeliveryNote,
      SalesDeliveryNotesActions.cancelDeliveryNote,
      (state) => ({ ...state, saving: true, error: null })
    ),
    // Status change successes - upsertOne
    on(
      SalesDeliveryNotesActions.confirmDeliveryNoteSuccess,
      SalesDeliveryNotesActions.shipDeliveryNoteSuccess,
      SalesDeliveryNotesActions.deliverDeliveryNoteSuccess,
      SalesDeliveryNotesActions.cancelDeliveryNoteSuccess,
      (state, { deliveryNote }) =>
        salesDeliveryNotesAdapter.upsertOne(deliveryNote, { ...state, saving: false })
    ),
    // Status change failures
    on(
      SalesDeliveryNotesActions.confirmDeliveryNoteFailure,
      SalesDeliveryNotesActions.shipDeliveryNoteFailure,
      SalesDeliveryNotesActions.deliverDeliveryNoteFailure,
      SalesDeliveryNotesActions.cancelDeliveryNoteFailure,
      (state, { error }) => ({ ...state, saving: false, error })
    ),
    on(SalesDeliveryNotesActions.clearDeliveryNotesError, (state) => ({ ...state, error: null }))
  ),
});

const { selectAll, selectEntities, selectTotal } = salesDeliveryNotesAdapter.getSelectors(
  salesDeliveryNotesFeature.selectSalesDeliveryNotesState
);

export const selectAllSalesDeliveryNotes = selectAll;
export const selectSalesDeliveryNoteEntities = selectEntities;
export const selectSalesDeliveryNotesTotal = selectTotal;
export const selectSalesDeliveryNotesMeta = salesDeliveryNotesFeature.selectMeta;
export const selectSalesDeliveryNotesLoading = salesDeliveryNotesFeature.selectLoading;
export const selectSalesDeliveryNotesSaving = salesDeliveryNotesFeature.selectSaving;
export const selectSalesDeliveryNotesError = salesDeliveryNotesFeature.selectError;
export const selectSalesDeliveryNotesLoaded = salesDeliveryNotesFeature.selectLoaded;
