import { createFeature, createReducer, on } from '@ngrx/store';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { SalesOrder } from '../../../models/sales-order.model';
import { PaginationMeta } from '../../../models/api.model';
import { SalesOrdersActions } from './orders.actions';

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

export const salesOrdersAdapter: EntityAdapter<SalesOrder> = createEntityAdapter<SalesOrder>();

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

export const salesOrdersFeature = createFeature({
  name: 'salesOrders',
  reducer: createReducer(
    initialState,
    on(SalesOrdersActions.loadOrders, (state, action) =>
      state.loaded && !action.force ? state : { ...state, loading: true, error: null }
    ),
    on(SalesOrdersActions.loadOrdersSuccess, (state, { orders, meta }) =>
      salesOrdersAdapter.setAll(orders, { ...state, meta, loading: false, loaded: true })
    ),
    on(SalesOrdersActions.loadOrdersFailure, (state, { error }) => ({
      ...state,
      loading: false,
      error,
    })),
    on(SalesOrdersActions.createOrder, (state) => ({ ...state, saving: true, error: null })),
    on(SalesOrdersActions.createOrderSuccess, (state, { order }) =>
      salesOrdersAdapter.addOne(order, { ...state, saving: false })
    ),
    on(SalesOrdersActions.createOrderFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    on(SalesOrdersActions.updateOrder, (state) => ({ ...state, saving: true, error: null })),
    on(SalesOrdersActions.updateOrderSuccess, (state, { order }) =>
      salesOrdersAdapter.upsertOne(order, { ...state, saving: false })
    ),
    on(SalesOrdersActions.updateOrderFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    on(SalesOrdersActions.deleteOrder, (state) => ({ ...state, saving: true, error: null })),
    on(SalesOrdersActions.deleteOrderSuccess, (state, { id }) =>
      salesOrdersAdapter.removeOne(id, { ...state, saving: false })
    ),
    on(SalesOrdersActions.deleteOrderFailure, (state, { error }) => ({
      ...state,
      saving: false,
      error,
    })),
    // Status change actions - set saving
    on(
      SalesOrdersActions.submitOrderApproval,
      SalesOrdersActions.approveOrder,
      SalesOrdersActions.rejectOrder,
      SalesOrdersActions.confirmOrder,
      SalesOrdersActions.createOrderDelivery,
      SalesOrdersActions.createOrderInvoice,
      SalesOrdersActions.cancelOrder,
      SalesOrdersActions.closeOrder,
      SalesOrdersActions.duplicateOrder,
      (state) => ({ ...state, saving: true, error: null })
    ),
    // Status change successes - upsertOne
    on(
      SalesOrdersActions.submitOrderApprovalSuccess,
      SalesOrdersActions.approveOrderSuccess,
      SalesOrdersActions.rejectOrderSuccess,
      SalesOrdersActions.confirmOrderSuccess,
      SalesOrdersActions.createOrderDeliverySuccess,
      SalesOrdersActions.createOrderInvoiceSuccess,
      SalesOrdersActions.cancelOrderSuccess,
      SalesOrdersActions.closeOrderSuccess,
      (state, { order }) => salesOrdersAdapter.upsertOne(order, { ...state, saving: false })
    ),
    on(SalesOrdersActions.duplicateOrderSuccess, (state, { order }) =>
      salesOrdersAdapter.addOne(order, { ...state, saving: false })
    ),
    // Status change failures
    on(
      SalesOrdersActions.submitOrderApprovalFailure,
      SalesOrdersActions.approveOrderFailure,
      SalesOrdersActions.rejectOrderFailure,
      SalesOrdersActions.confirmOrderFailure,
      SalesOrdersActions.createOrderDeliveryFailure,
      SalesOrdersActions.createOrderInvoiceFailure,
      SalesOrdersActions.cancelOrderFailure,
      SalesOrdersActions.closeOrderFailure,
      SalesOrdersActions.duplicateOrderFailure,
      (state, { error }) => ({ ...state, saving: false, error })
    ),
    on(SalesOrdersActions.clearOrdersError, (state) => ({ ...state, error: null }))
  ),
});

const { selectAll, selectEntities, selectTotal } = salesOrdersAdapter.getSelectors(
  salesOrdersFeature.selectSalesOrdersState
);

export const selectAllSalesOrders = selectAll;
export const selectSalesOrderEntities = selectEntities;
export const selectSalesOrdersTotal = selectTotal;
export const selectSalesOrdersMeta = salesOrdersFeature.selectMeta;
export const selectSalesOrdersLoading = salesOrdersFeature.selectLoading;
export const selectSalesOrdersSaving = salesOrdersFeature.selectSaving;
export const selectSalesOrdersError = salesOrdersFeature.selectError;
export const selectSalesOrdersLoaded = salesOrdersFeature.selectLoaded;
