import { createModel } from '@rematch/core'

import { EventRecord, EventPhase, EventStage, EventPhaseLog } from '../../types/core'

import { RootModel } from '.'


const isPhaseOutOfOrder = (loggedPhases: EventPhaseLog, newPhase: EventPhase) => {
  const correctOrder: EventStage[] = ['triggered', 'enriched', 'delivered']

  if (!correctOrder.includes(newPhase.stage)) {
    throw new Error(`Unknown phase: ${newPhase.stage}`)
  }

  const latterStages = correctOrder.slice(correctOrder.indexOf(newPhase.stage))

  return latterStages.some((stage) => typeof loggedPhases?.[stage] === 'object')
}

const defaultState = () => ({} as Record<string, EventRecord>)

export const events = createModel<RootModel>()({
  state: defaultState(),
  reducers: {
    traceEvent(state, phase: EventPhase) {
      const { id } = phase

      // other event phases cannot be safely traced if we don't have lift off details
      if (!state[id] && phase.stage !== 'triggered') {
        // this is a silent fail instead of an error because the inspector could be
        // docking with the page/app amidst an event being processed, so we just ignore
        return state
      }

      if (isPhaseOutOfOrder(state[id]?.phases, phase)) {
        throw new Error(`${phase.stage} out of order`)
      }

      state[id] = {
        id,
        event: phase.event,
        phases: {
          ...state[id]?.phases,
          [phase.stage]: phase
        }
      }

      return state
    }
  },
  effects: {}
})
