import { Process, CustomerFormState } from '../../models/process.model';
import { State, Action, StateContext, Store, Select, Selector } from '@ngxs/store';
import * as actions from '../actions/process.actions';
import { ProductService } from '../../services/product.service';
import { RecentArticleSearch } from '../../models/recent-article-search.model';
import { LoadRecentProducts, AddSelectedProduct, DeleteProductsForProcess } from '../actions/product.actions';
import { PopLastBreadcrumbs, DeleteBreadcrumbsForProcess } from '../actions/breadcrumb.actions';
import { SetCartToProcess, DeleteCart } from '../actions/cart.actions';
import { DeleteSelectedFiltersForProcess, LoadFilters, SetFilterType } from '../actions/filter.actions';
import { tap } from 'rxjs/operators';
import { AppState, AppStateModel } from './app.state';
import { AppSetCurrentProcess, AppDeleteProcess, AppAddProcess, AppUserDataSync } from '../actions/app.actions';
import { patch, append } from '@ngxs/store/operators';
import { CurrentCustomerPageLoaded } from '../actions/customer.actions';
import { UserStateSyncData } from '../../models/user-state-sync.model';
import { RadioButtonGroup } from '@libs/ui/lib/radio-button-group';
import { RadioButton } from '@libs/ui';
import { SetPreviusPath } from '../actions/process.actions';
import { isNullOrUndefined } from 'util';
import { DeleteCollectingShelfForProcess } from '../actions/collecting-shelf.action';
import { FilterType } from '../../models/filter-type.enum';
import { Injectable } from '@angular/core';

export interface ProcessStateModel {
  processes: { [id: number]: Process };
  recentArticles: RecentArticleSearch[];
}

@State<ProcessStateModel>({
  name: 'processes',
  defaults: {
    processes: [],
    recentArticles: [],
  },
})
@Injectable()
export class ProcessState {
  constructor(protected productService: ProductService, private store: Store) {}

  @Selector([AppState])
  static userData(process: ProcessStateModel, state: AppStateModel) {
    const processId = state.currentProcesssId;
    return processId && process.processes[processId] ? process.processes[processId].userData : null;
  }

  @Action(actions.AddProcess)
  add(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddProcess) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const processExists = state.processes[payload.id] !== undefined;
    if (processExists) {
      return;
    }
    const uniqueIdentifier = new Date().getUTCMilliseconds() + Math.random();
    const processes = {
      ...state.processes,
      [payload.id]: <Process>{
        ...payload,
        new: true,
        customerFormState: CustomerFormState.CREATE,
        uniqueIdentifier: uniqueIdentifier,
        ordersOpenend: false,
        closeDirectlyTab: false,
        articleSearchErrorStatus: false,
        customerNotificationFlag: false,
        productSearchFilters: {
          archiveFilters: false,
          radioButtonGroup: <RadioButtonGroup>{
            radioButtons: [
              <RadioButton>{
                id: 1,
                name: 'Autor',
                key: 'author',
                selected: false,
              },
              <RadioButton>{
                id: 2,
                name: 'Titel',
                key: 'title',
                selected: false,
              },
              <RadioButton>{
                id: 3,
                name: 'Verlag',
                key: 'publisher',
                selected: false,
              },
            ],
          },
        },
      },
    };
    ctx.patchState({ processes });
    this.store
      .dispatch(new AppAddProcess(payload.id))
      .toPromise()
      .then(() => {
        this.store.dispatch(new SetFilterType(FilterType.Default));
        this.store.dispatch(new LoadFilters(FilterType.Default));
        this.store.dispatch(new SetCartToProcess());
      });
  }

  @Action(actions.AddCartToProcess)
  addCart(ctx: StateContext<ProcessStateModel>, { cartId }: actions.AddCartToProcess) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);

    const isValidCustomerProcess = (processId) => processId > 0;

    if (!isValidCustomerProcess(currentProcessId)) {
      return;
    }

    const process = { ...currentProcesses[currentProcessId], cartId: cartId };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;

    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.DeleteProcess)
  delete(ctx: StateContext<ProcessStateModel>, { payload }: actions.DeleteProcess) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const currentProcess = state.processes[currentProcessId];
    if (!currentProcess) {
      return;
    }
    const recentArticles = state.recentArticles;
    if (currentProcessId && currentProcessId === payload.id) {
      const processIds = this.store.selectSnapshot(AppState.getProcessIds);
      const indexOfProcessToDelete = processIds.indexOf(payload.id);
      if (indexOfProcessToDelete !== 0) {
        this.store.dispatch(new AppSetCurrentProcess(processIds[indexOfProcessToDelete - 1]));
      } else if (indexOfProcessToDelete === 0 && processIds.length > 1) {
        this.store.dispatch(new AppSetCurrentProcess(processIds[1]));
      }
    }
    const processes = { ...state.processes };
    delete processes[payload.id];
    ctx.patchState({ processes });
    this.syncApiState(currentProcessId, processes, recentArticles);
    this.store.dispatch(new AppDeleteProcess(payload.id));
    this.store.dispatch(new DeleteCart(currentProcess.cartId));
    this.deleteProcessDependencies(ctx.dispatch, payload.id);
  }

  deleteProcessDependencies(dispatch: any, processId: number) {
    dispatch(new DeleteProductsForProcess(processId));
    dispatch(new DeleteBreadcrumbsForProcess(processId));
    dispatch(new DeleteSelectedFiltersForProcess(processId));
    dispatch(new DeleteCollectingShelfForProcess(processId));
  }

  @Action(actions.AddSearch)
  addSearch(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddSearch) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = { ...currentProcesses[currentProcessId], search: payload };
    ctx.setState(this.updateProcess(process));

    const stateProcess = {
      ...currentProcesses[currentProcessId],
      search: { ...payload, firstLoad: false },
    };
    const processes = { ...currentProcesses };
    processes[process.id] = stateProcess;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.AddCustomerSearch)
  addCustomerSearch(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddCustomerSearch) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      customerSearch: payload,
    };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.ChangeCurrentRoute)
  changeCurrentRoute(ctx: StateContext<ProcessStateModel>, { payload, removeLastBreadcrumb, queryParams }: actions.ChangeCurrentRoute) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const recentArticles = state.recentArticles;

    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId] && payload) {
      let previousRoute = currentProcesses[currentProcessId].currentRoute;
      const pathData = payload.split('/');
      const lastCrumbInCustomerMenu = pathData.length > 0 ? pathData[pathData.length - 1] : '';

      if (
        payload.substring(0, 14) === '/customer/edit' &&
        lastCrumbInCustomerMenu !== 'billing' &&
        lastCrumbInCustomerMenu !== 'delivery'
      ) {
        previousRoute = '/customer/results';
      } else if (payload.substring(0, 14) === '/customer/edit') {
        pathData.pop();
        previousRoute = pathData.join('/');
      }

      const process = {
        ...currentProcesses[currentProcessId],
        previousRoute: previousRoute,
        currentRoute: payload,
        new: false,
        currentRouteQueryParams: queryParams,
      };

      ctx.setState(this.updateProcess(process));
      if (removeLastBreadcrumb) {
        this.store.dispatch(new PopLastBreadcrumbs(payload));
      }

      const processes = { ...currentProcesses };
      processes[process.id] = process;
      this.syncApiState(currentProcessId, processes, recentArticles);
    }
  }

  @Action(LoadRecentProducts)
  loadRecentProducts(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    return this.productService.getRecentSearches().pipe(
      tap((products: RecentArticleSearch[]) => {
        if (products) {
          ctx.patchState({
            ...state,
            recentArticles: products.reverse().slice(0, 5),
          });
        }
      })
    );
  }

  @Action(SetPreviusPath)
  UpdatePreviusPath(ctx: StateContext<ProcessStateModel>, { path }: SetPreviusPath) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      previousRoute: path,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(AddSelectedProduct)
  AddSelectedProduct(ctx: StateContext<ProcessStateModel>, { payload, index }: AddSelectedProduct) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      selectedItem: payload,
      productScrollTo: index,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.PreventProductLoad)
  preventProductLoad(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      preventLoading: true,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.AllowProductLoad)
  allowProductLoad(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      preventLoading: false,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.UpdateCurrentRouteQueryParams)
  updateCurrentRouteQueryParams(ctx: StateContext<ProcessStateModel>, { queryParams }: actions.UpdateCurrentRouteQueryParams) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      currentRouteQueryParams: queryParams,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(CurrentCustomerPageLoaded)
  setCurrentCustomerPage(ctx: StateContext<ProcessStateModel>, { page }: CurrentCustomerPageLoaded) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      CurrentCustomerPageLoaded: page,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.EmptyFinishedOrders)
  emptyFinishedOrders(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      finishedOrder: undefined,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.SetArticleSearchErrorStatus)
  setArticleSearchErrorStatus(ctx: StateContext<ProcessStateModel>, { status }: actions.SetArticleSearchErrorStatus) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const process = {
        ...currentProcesses[currentProcessId],
        articleSearchErrorStatus: status,
      };
      ctx.setState(this.updateProcess(process));
    }
  }

  @Action(actions.SetShelfSearch)
  setShelfSearch(ctx: StateContext<ProcessStateModel>, { shelfSearch }: actions.SetShelfSearch) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const process = {
        ...currentProcesses[currentProcessId],
        shelfSearch: shelfSearch,
      };
      ctx.setState(this.updateProcess(process));
    }
  }

  @Action(actions.SetCustomerNotificationFlag)
  setCustomerNotificationFlag(ctx: StateContext<ProcessStateModel>, { flag }: actions.SetCustomerNotificationFlag) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const process = {
        ...currentProcesses[currentProcessId],
        customerNotificationFlag: flag,
      };
      ctx.setState(this.updateProcess(process));
    }
  }

  @Action(actions.SetProcessNewStatusToFalse)
  setProcessNewStatusToFalse(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (state) {
      const currentProcesses = state.processes;
      const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
      if (currentProcesses[currentProcessId] && currentProcesses[currentProcessId].id && currentProcesses[currentProcessId].new) {
        const process = { ...currentProcesses[currentProcessId], new: false };
        ctx.setState(this.updateProcess(process));
      }
    }
  }

  @Action(actions.SetOnlineCustomerCreationStatus)
  setOnlineCustomerCreationStatus(ctx: StateContext<ProcessStateModel>, { error }: actions.SetOnlineCustomerCreationStatus) {
    const state = ctx.getState();
    if (state) {
      const currentProcesses = state.processes;
      const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
      if (currentProcesses[currentProcessId] && currentProcesses[currentProcessId].id) {
        const process = {
          ...currentProcesses[currentProcessId],
          onlineCustomerCreationError: error,
        };
        ctx.setState(this.updateProcess(process));
      }
    }
  }

  @Action(actions.ClearPartOfCustomerCreationStatus)
  clearPartOfCustomerCreationStatus(ctx: StateContext<ProcessStateModel>, { field }: actions.ClearPartOfCustomerCreationStatus) {
    const state = ctx.getState();
    if (state) {
      const currentProcesses = state.processes;
      const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
      if (currentProcesses[currentProcessId] && currentProcesses[currentProcessId].id) {
        const onlineCustomerCreationError = currentProcesses[currentProcessId].onlineCustomerCreationError;
        if (onlineCustomerCreationError && onlineCustomerCreationError.error) {
          const updatedOnlineCustomerCreationError = {
            ...onlineCustomerCreationError,
            invalidProperties: {
              ...onlineCustomerCreationError.invalidProperties,
              [field]: undefined,
            },
          };
          if (Object.keys(updatedOnlineCustomerCreationError.invalidProperties).length < 1) {
            updatedOnlineCustomerCreationError.error = false;
          }
          const process = {
            ...currentProcesses[currentProcessId],
            onlineCustomerCreationError: updatedOnlineCustomerCreationError,
          };
          ctx.setState(this.updateProcess(process));
        }
      }
    }
  }

  @Action(actions.UpdateProcessName)
  updateProcessName(ctx: StateContext<ProcessStateModel>, { payload }: actions.UpdateProcessName) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = { ...currentProcesses[currentProcessId], name: payload };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.UpdateCustomerFormState)
  updateCustomerFormState(ctx: StateContext<ProcessStateModel>, { payload }: actions.UpdateCustomerFormState) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      customerFormState: payload,
    };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.RemoveProcessNewState)
  removeProcessNewState(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const process = { ...currentProcesses[currentProcessId], new: false };
      ctx.setState(this.updateProcess(process));

      const processes = { ...currentProcesses };
      processes[process.id] = process;
      this.syncApiState(currentProcessId, processes, recentArticles);
    }
  }

  @Action(actions.AddCustomerId)
  addCustomerId(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddCustomerId) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const currentCustomerIds = currentProcesses[currentProcessId].customerIds;
    if (!currentCustomerIds.includes(payload)) {
      const customerIds = append([payload])(currentCustomerIds);
      const process = { ...currentProcesses[currentProcessId], customerIds };
      ctx.setState(this.updateProcess(process));

      const processes = { ...currentProcesses };
      processes[process.id] = process;
      this.syncApiState(currentProcessId, processes, recentArticles);
    }
  }

  @Action(actions.AddCustomerIds)
  addCustomerIds(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddCustomerIds) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcessId < 1) {
      return;
    }
    const process = {
      ...currentProcesses[currentProcessId],
      customerIds: payload,
    };
    const processes = { ...currentProcesses };
    processes[process.id] = process;
    ctx.patchState({ processes: processes });
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.RemoveCustomerId)
  removeCustomerId(ctx: StateContext<ProcessStateModel>, { payload }: actions.RemoveCustomerId) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const currentCustomerIds = currentProcesses[currentProcessId].customerIds;
    const customerIds = currentCustomerIds.filter((t) => t !== payload);
    const process = { ...currentProcesses[currentProcessId], customerIds };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.SetActiveCustomer)
  setActiveCustomerId(ctx: StateContext<ProcessStateModel>, { payload }: actions.SetActiveCustomer) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      activeCustomer: payload,
      finishedOrderCustomer: payload,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.SetDetailsCustomer)
  setDetailsustomerId(ctx: StateContext<ProcessStateModel>, { payload }: actions.SetDetailsCustomer) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      detailsCustomer: payload,
    };
    ctx.setState(this.updateProcess(process));
  }

  @Action(actions.ResetProcess)
  resetProcess(ctx: StateContext<ProcessStateModel>, {}: actions.ResetProcess) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const oldProcess = { ...currentProcesses[currentProcessId] };
    if (!oldProcess) {
      return;
    }
    const newProcess = <Process>{
      id: oldProcess.id,
      cartId: oldProcess.cartId,
      activeCustomer: undefined,
      finishedOrderCustomer: oldProcess.finishedOrderCustomer,
      detailsCustomer: undefined,
      customerFormState: CustomerFormState.CREATE,
      currentRoute: oldProcess.currentRoute,
      new: false,
      name: `Vorgang ${oldProcess.id}`,
      finishedOrder: oldProcess.finishedOrder,
      closeDirectlyTab: oldProcess.closeDirectlyTab,
      uniqueIdentifier: oldProcess.uniqueIdentifier,
      ordersOpenend: oldProcess.ordersOpenend,
      articleSearchErrorStatus: oldProcess.articleSearchErrorStatus,
      productSearchFilters: oldProcess.productSearchFilters,
      customerNotificationFlag: false,
    };
    const processes = { ...currentProcesses };
    processes[oldProcess.id] = newProcess;

    ctx.setState(this.updateProcess(newProcess));

    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.SetFinishedOrderData)
  setFinishedOrder(ctx: StateContext<ProcessStateModel>, { order }: actions.SetFinishedOrderData) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      finishedOrder: order,
    };
    const processes = { ...currentProcesses };
    processes[process.id] = process;
    ctx.patchState({ processes: processes });

    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.ReloadProcessData)
  reloadProcesses(ctx: StateContext<ProcessStateModel>, { processes, recentArticles }: actions.ReloadProcessData) {
    const isValidProcess = (process: Process) => {
      return process.id && process.name;
    };

    const validProcesses = Object.entries(processes)
      .filter(([_, process]) => isValidProcess(process))
      .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});

    ctx.setState({
      processes: { ...validProcesses },
      recentArticles: recentArticles,
    });
  }

  @Action(actions.CustomerOrdersVisited)
  ordersVisited(ctx: StateContext<ProcessStateModel>, { visited }: actions.CustomerOrdersVisited) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      ordersOpenend: visited,
    };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.SetProcessProductFilters)
  updateProductFilters(ctx: StateContext<ProcessStateModel>, { filters }: actions.SetProcessProductFilters) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      productSearchFilters: filters,
    };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  @Action(actions.ResetProcessProductFilters)
  resetProductFilters(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const currentProductSearchFilters = currentProcesses[currentProcessId].productSearchFilters;

      try {
        const process = {
          ...currentProcesses[currentProcessId],
          productSearchFilters: {
            archiveFilters: false,
            radioButtonGroup: <RadioButtonGroup>{
              radioButtons: [
                <RadioButton>{
                  id: 1,
                  name: 'Autor',
                  key: 'author',
                  selected: false,
                },
                <RadioButton>{
                  id: 2,
                  name: 'Titel',
                  key: 'title',
                  selected: false,
                },
                <RadioButton>{
                  id: 3,
                  name: 'Verlag',
                  key: 'publisher',
                  selected: false,
                },
              ],
            },
          },
        };
        ctx.setState(this.updateProcess(process));
      } catch (error) {
        console.error(error);
      }
    }
  }

  @Action(actions.SetSelectedItemIfMissingOrChanged)
  setSelectedItemIfMissingOrChanged(ctx: StateContext<ProcessStateModel>, { item }: actions.SetSelectedItemIfMissingOrChanged) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    if (currentProcesses && currentProcessId && currentProcesses[currentProcessId]) {
      const process = currentProcesses[currentProcessId];
      let updatedProcess: Process = { ...process };
      let changed = false;
      if (isNullOrUndefined(process.selectedItem)) {
        updatedProcess = { ...process, selectedItem: item };
        changed = true;
      } else if (process.selectedItem && item && process.selectedItem.id !== item.id) {
        updatedProcess = { ...process, selectedItem: item };
        changed = true;
      }
      if (changed) {
        ctx.setState(this.updateProcess(updatedProcess));
      }
    }
  }

  @Action(actions.RemoveSelectedItem)
  removeSelectedItem(ctx: StateContext<ProcessStateModel>) {
    const state = ctx.getState();
    if (!state) {
      return;
    }
    const currentProcesses = state.processes;
    const recentArticles = state.recentArticles;
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    const process = {
      ...currentProcesses[currentProcessId],
      selectedItem: undefined,
    };
    ctx.setState(this.updateProcess(process));

    const processes = { ...currentProcesses };
    processes[process.id] = process;
    this.syncApiState(currentProcessId, processes, recentArticles);
  }

  updateProcess<T extends Process>(process: T) {
    if (process.id === undefined) {
      return;
    }
    return patch({
      processes: patch({ [process.id]: process }),
    });
  }

  private syncApiState(currentProcesssId: number, processes: { [id: number]: Process }, recentArticles: RecentArticleSearch[]) {
    const userSyncData: UserStateSyncData = {
      currentProcesssId,
      processes,
      recentArticles,
    };
    const userData = JSON.stringify(userSyncData);
    this.store.dispatch(new AppUserDataSync(userData));
  }
}
