import { State, Action, StateContext, Store } from '@ngxs/store';
import * as actions from '../actions/collecting-shelf.action';
import { AppState } from './app.state';
import { UserStateSyncData } from '../../models/user-state-sync.model';
import { AppUserDataSync } from '../actions/app.actions';
import { CollectingShelfOrder } from '../../models/collecting-shelf-order.model';
import { OrderDTO } from '@swagger/oms';
import { Injectable } from '@angular/core';

export interface CollectingShelfStateModel {
  orders: { [key: number]: { [key: number]: CollectingShelfOrder } };
  editOrder: { [id: number]: OrderDTO };
  cachedSearchResults: { [id: number]: { result: CollectingShelfOrder[]; hits: number } };
  useCache: { [id: number]: boolean };
}

@State<CollectingShelfStateModel>({
  name: 'orders',
  defaults: {
    orders: [],
    editOrder: {},
    cachedSearchResults: {},
    useCache: {},
  },
})
@Injectable()
export class CollectingShelfState {
  constructor(private store: Store) {}

  @Action(actions.SetShelfOrders)
  setShelfOrders(ctx: StateContext<CollectingShelfStateModel>, { orders }: actions.SetShelfOrders) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (!currentProcessId) {
      return;
    }

    const customerOrders = { ...state.orders };

    let items = {};
    if (customerOrders[currentProcessId]) {
      items = { ...customerOrders[currentProcessId] };
    }

    orders.forEach((item: CollectingShelfOrder) => {
      if (item && !items[item.orderItemSubsetId]) {
        items[item.orderItemSubsetId] = item;
        customerOrders[currentProcessId] = items;
      }
    });

    ctx.patchState({ orders: customerOrders });
    this.syncApiState(customerOrders, state.editOrder, state.cachedSearchResults, state.useCache);
  }

  @Action(actions.ClearShelfOrdersForProcess)
  clearShelfOrdersForProcess(ctx: StateContext<CollectingShelfStateModel>) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (!currentProcessId) {
      return;
    }

    const customerOrders = { ...state.orders };
    customerOrders[currentProcessId] = {};
    ctx.patchState({ orders: customerOrders });
    this.syncApiState(customerOrders, state.editOrder, state.cachedSearchResults, state.useCache);
  }

  @Action(actions.ClearCachedResults)
  clearShelfCachedResults(ctx: StateContext<CollectingShelfStateModel>) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (!currentProcessId) {
      return;
    }

    const cachedSearchResults = { ...state.cachedSearchResults };
    cachedSearchResults[currentProcessId] = undefined;
    ctx.patchState({ cachedSearchResults: cachedSearchResults });
    this.syncApiState(state.orders, state.editOrder, cachedSearchResults, state.useCache);
  }

  @Action(actions.SetEditOrder)
  setEditOrder(ctx: StateContext<CollectingShelfStateModel>, { order }: actions.SetEditOrder) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (state && currentProcessId) {
      const editOrder = { ...state.editOrder, [currentProcessId]: order };
      ctx.patchState({ editOrder });
      this.syncApiState(state.orders, editOrder, state.cachedSearchResults, state.useCache);
    }
  }

  @Action(actions.SetCachedResults)
  setCachedResults(ctx: StateContext<CollectingShelfStateModel>, { processCachedSearchResults }: actions.SetCachedResults) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (state && currentProcessId) {
      const cachedSearchResults = { ...state.cachedSearchResults, [currentProcessId]: processCachedSearchResults };
      ctx.patchState({ cachedSearchResults });
      this.syncApiState(state.orders, state.editOrder, cachedSearchResults, state.useCache);
    }
  }

  @Action(actions.DeleteCollectingShelfForProcess)
  delete(ctx: StateContext<CollectingShelfStateModel>, { processId }: actions.DeleteCollectingShelfForProcess) {
    const state = ctx.getState();
    if (state) {
      const orders = { ...state.orders, [processId]: undefined };
      const editOrder = { ...state.editOrder, [processId]: undefined };
      const cachedSearchResults = { ...state.cachedSearchResults, [processId]: undefined };
      const useCache = { ...state.useCache, [processId]: undefined };
      ctx.patchState({ orders, editOrder, cachedSearchResults });
      this.syncApiState(orders, editOrder, cachedSearchResults, useCache);
    }
  }

  @Action(actions.SetCollectingShelfCacheState)
  setCollectingShelfCacheState(ctx: StateContext<CollectingShelfStateModel>, { useCache }: actions.SetCollectingShelfCacheState) {
    const state = ctx.getState();
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    if (state && currentProcessId) {
      const updatedUseCache = { ...state.useCache, [currentProcessId]: useCache };
      ctx.patchState({ useCache: updatedUseCache });
      this.syncApiState(state.orders, state.editOrder, state.cachedSearchResults, updatedUseCache);
    }
  }

  @Action(actions.ReloadCollectingShelfData)
  reloadCollectingShelfData(
    ctx: StateContext<CollectingShelfStateModel>,
    { orders, editOrder, cachedSearchResults, useCache }: actions.ReloadCollectingShelfData
  ) {
    ctx.setState({ orders, editOrder, cachedSearchResults, useCache });
  }

  private syncApiState(
    shelfOrders: { [key: number]: { [key: number]: CollectingShelfOrder } },
    editOrder: { [id: number]: OrderDTO },
    cachedSearchResults: { [id: number]: { result: CollectingShelfOrder[]; hits: number } },
    useCache: { [id: number]: boolean }
  ) {
    const userSyncData: UserStateSyncData = {
      shelfOrders: shelfOrders,
      editOrder: editOrder,
      cachedSearchResults: cachedSearchResults,
      useCache: useCache,
    };
    const userData = JSON.stringify(userSyncData);
    this.store.dispatch(new AppUserDataSync(userData));
  }
}
