import type {
  ActionLog,
  DefinitionInject,
  MilestoneState,
} from '@inject/graphql/fragment-types'
import setsEqual from '@inject/shared/utils/setsEqual'

export interface selectedReducerStateProps {
  selectedDataType?: 'ACTIONS' | 'MILESTONES' | 'EMAILS' | 'AUTO_INJECTS'
  actionLog?: ActionLog
  milestoneState?: MilestoneState
  injectGroup?: DefinitionInject[]
}

export interface selectedReducerActionProps {
  type:
    | 'selectActions'
    | 'selectMilestones'
    | 'selectEmails'
    | 'selectCategories'
    | 'resetSelection'
  actionLog?: ActionLog
  milestoneState?: MilestoneState
  injectGroup?: DefinitionInject[]
}

const injectGroupsEqual = (a: DefinitionInject[], b: DefinitionInject[]) =>
  a.every((category, i) => b[i].id === category.id)

const selectedReducer = (
  state: selectedReducerStateProps,
  action: selectedReducerActionProps
): selectedReducerStateProps => {
  switch (action.type) {
    case 'selectActions':
      if (
        state.selectedDataType === 'ACTIONS' &&
        state.actionLog?.id === action.actionLog?.id
      ) {
        return selectedReducer(state, { type: 'resetSelection' })
      }

      return {
        selectedDataType: 'ACTIONS',
        actionLog: action.actionLog,
      }
    case 'selectMilestones':
      if (state.selectedDataType === 'MILESTONES') {
        if (!state.milestoneState || !action.milestoneState) {
          throw new Error('milestoneState null when MILESTONES selected')
        }

        // milestoneStatesEqual
        if (
          state.milestoneState !== null &&
          action.milestoneState !== null &&
          state.milestoneState.milestone.id ===
            action.milestoneState.milestone.id &&
          setsEqual(
            new Set(state.milestoneState.teamIds),
            new Set(action.milestoneState.teamIds)
          )
        ) {
          return selectedReducer(state, { type: 'resetSelection' })
        }
      }

      return {
        selectedDataType: 'MILESTONES',
        milestoneState: action.milestoneState,
      }
    case 'selectEmails':
      if (
        state.selectedDataType === 'EMAILS' &&
        state.actionLog?.id === action.actionLog?.id
      ) {
        return selectedReducer(state, { type: 'resetSelection' })
      }

      return {
        selectedDataType: 'EMAILS',
        actionLog: action.actionLog,
      }
    case 'selectCategories':
      if (state.selectedDataType === 'AUTO_INJECTS') {
        if (!state.injectGroup || !action.injectGroup) {
          throw new Error('categories null when AUTO_INJECTS selected')
        }

        if (injectGroupsEqual(state.injectGroup, action.injectGroup)) {
          return selectedReducer(state, { type: 'resetSelection' })
        }
      }

      return {
        selectedDataType: 'AUTO_INJECTS',
        injectGroup: action.injectGroup,
      }
    case 'resetSelection':
      return {}
    default:
      throw new Error('unknown action')
  }
}

export default selectedReducer
