text: // @flow
  import assert from 'assert'
  import produce from 'immer'
  import { stripNoOpCommands } from '../utils/stripNoOpCommands'
  import { forAspirate } from './forAspirate'
  import { forDispense } from './forDispense'
  import { forBlowout } from './forBlowout'
  import { forDropTip } from './forDropTip'
  import { forPickUpTip } from './forPickUpTip'
  import { forEngageMagnet, forDisengageMagnet } from './magnetUpdates'
  import {
    forThermocyclerAwaitBlockTemperature,
    forThermocyclerAwaitLidTemperature,
    forThermocyclerAwaitProfileComplete,
    forThermocyclerCloseLid,
    forThermocyclerDeactivateBlock,
    forThermocyclerDeactivateLid,
    forThermocyclerOpenLid,
    forThermocyclerRunProfile,
    forThermocyclerSetTargetBlockTemperature,
    forThermocyclerSetTargetLidTemperature,
  } from './thermocyclerUpdates'
  
  import {
    forAwaitTemperature,
    forSetTemperature,
    forDeactivateTemperature,
  } from './temperatureUpdates'
  import type { Command } from '@opentrons/shared-data/protocol/flowTypes/schemaV6'
  import type {
    InvariantContext,
    RobotState,
    RobotStateAndWarnings,
  } from '../types'
  
  // WARNING this will mutate the prevRobotState
  function _getNextRobotStateAndWarningsSingleCommand(
    command: Command,
    invariantContext: InvariantContext,
    robotStateAndWarnings: RobotStateAndWarnings
  ): void {
    assert(command, 'undefined command passed to getNextRobotStateAndWarning')
  
    switch (command.command) {
      case 'aspirate':
        forAspirate(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'dispense':
        forDispense(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'blowout':
        forBlowout(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'dropTip':
        forDropTip(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'pickUpTip':
        forPickUpTip(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'magneticModule/engageMagnet':
        forEngageMagnet(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'magneticModule/disengageMagnet':
        forDisengageMagnet(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'touchTip':
      case 'delay':
      case 'airGap':
      case 'dispenseAirGap':
      case 'moveToWell':
        // these commands don't have any effects on the state
        break
      case 'temperatureModule/setTargetTemperature':
        forSetTemperature(command.params, invariantContext, robotStateAndWarnings)
        break
      case 'temperatureModule/deactivate':
        forDeactivateTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'temperatureModule/awaitTemperature':
        forAwaitTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/setTargetBlockTemperature':
        forThermocyclerSetTargetBlockTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/setTargetLidTemperature':
        forThermocyclerSetTargetLidTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/awaitBlockTemperature':
        forThermocyclerAwaitBlockTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/awaitLidTemperature':
        forThermocyclerAwaitLidTemperature(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/deactivateBlock':
        forThermocyclerDeactivateBlock(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/deactivateLid':
        forThermocyclerDeactivateLid(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/closeLid':
        forThermocyclerCloseLid(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/openLid':
        forThermocyclerOpenLid(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/runProfile':
        forThermocyclerRunProfile(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
      case 'thermocycler/awaitProfileComplete':
        forThermocyclerAwaitProfileComplete(
          command.params,
          invariantContext,
          robotStateAndWarnings
        )
        break
  
      default:
        assert(
          false,
          `unknown command: ${command.command} passed to getNextRobotStateAndWarning`
        )
    }
  }
  
  export function getNextRobotStateAndWarningsSingleCommand(
    command: Command,
    invariantContext: InvariantContext,
    prevRobotState: RobotState
  ): RobotStateAndWarnings {
    const prevState = {
      warnings: [],
      robotState: prevRobotState,
    }
    return produce(prevState, draft => {
      _getNextRobotStateAndWarningsSingleCommand(command, invariantContext, draft)
    })
  }
  
  // Get next state after multiple commands
  export function getNextRobotStateAndWarnings(
    commands: Array<Command>,
    invariantContext: InvariantContext,
    initialRobotState: RobotState
  ): RobotStateAndWarnings {
    const prevState = {
      warnings: [],
      robotState: initialRobotState,
    }
    const strippedCommands = stripNoOpCommands(commands)
    return produce(prevState, draft => {
      strippedCommands.forEach(command => {
        _getNextRobotStateAndWarningsSingleCommand(
          command,
          invariantContext,
          draft
        )
      })
    })
  }
  