export const initialState = {
  time: null, // Time obj 'hours', 'minutes', 'meridiem'
  selected: 'none',
  redrawCounter: 0,
  SELECTED_RANGE: {
    none: { start: 0, end: 0 },
    hours: { start: 0, end: 2, previous: 'meridiem', next: 'minutes', pattern: /^[0-9]+$/ },
    minutes: { start: 3, end: 5, previous: 'hours', next: 'meridiem', pattern: /^[0-9]+$/ },
    meridiem: { start: 6, end: 8, previous: 'minutes', next: 'hours', pattern: /^[AMP]/ }
  }
}
  
  
export const reducer = (state, action) => {
  let _time; let _selected
  
  switch (action.type) {
    // DETERMINE WHICH ELEMENT OF TIME INPUT TO SELECT/HIGHLIGHT (i.e. HOURS, MINS, AM/PM)
    case 'clickToSelect':
      const selectionStart = { action }
      _selected = 'meridiem'
      if (selectionStart < state.SELECTED_RANGE.hours.end + 1) {
        _selected = 'hours'
      } else if (selectionStart < state.SELECTED_RANGE.minutes.end) {
        _selected = 'minutes'
      } 
      return {
        ...state,
        selected: _selected,
        redrawCounter: state.redrawCounter + 1
      }
    // DETERMIN IF INPUT IS VALID RELATIVE TO 'hour', 'minutes', 'meridiem'
    case 'validateInput':
      const { value, keyDownTimer } = action
      let [_hours, _minutes, _meridiem] = (value.trim()).split(/[:\s]/)
      const _timeNow = Date.now()
      // UPDATE HOURS
      if (state.selected === 'hours') {
        if (state.SELECTED_RANGE.hours.pattern.test(_hours) === false) break
        _hours = Number(_hours)
        const _prevHours = Number(state.time.hours)
        let _hoursFormatted
        if (_timeNow - keyDownTimer.current < 500) {
          _hoursFormatted = (_prevHours === 1 && _hours < 3) ? '1' + _hours : _hours === 0 ? state.time.hours : ' ' + _hours
        } else {
          _hoursFormatted = _hours === 0 ? state.time.hours : ' ' + _hours
        } 
        return {
          ...state,
          time:  {...state.time, hours: _hoursFormatted },
          redrawCounter: state.redrawCounter + 1
        }
      }
      // UPDATE MINUTES
      if (state.selected === 'minutes') {
        if (state.SELECTED_RANGE.minutes.pattern.test(_minutes) === false) break
        _minutes = Number(_minutes)
        let _minutesFormatted
        const _prevMinutes = Number(state.time.minutes)
        if (_timeNow - keyDownTimer.current < 500) {
          _minutesFormatted = _prevMinutes < 6 ? `${_prevMinutes}${_minutes}` : '0' + _minutes
        } else {
          _minutesFormatted = '0' + _minutes
        }
        return { 
          ...state,
          time: {...state.time, minutes: _minutesFormatted },
          redrawCounter: state.redrawCounter + 1
        }
      }
      // UPDATE MERIDIEM
      if (state.selected === 'meridiem') {
        let _meridiemFormatted
        const _prevMeridiem = state.time.meridiem
        if (_meridiem[0].toUpperCase() === 'A' || _meridiem[0].toUpperCase() === 'P') {
          _meridiemFormatted = `${_meridiem[0].toUpperCase()}M`
        } else {
          _meridiemFormatted = _prevMeridiem
        }
        return { 
          ...state,
          time: {...state.time, meridiem: _meridiemFormatted },
          redrawCounter: state.redrawCounter + 1
        }
      }
      return {
        ...state,
        redrawCounter: state.redrawCounter + 1
      }
    // DETERMINE IF 'Enter', 'Tab' OR ARROW KEYS HAVE BEEN PRESSED 
    case 'keyDown':
      const { event, textFieldRef } = action
      const { code } = event
      if (code === 'Enter') {
        textFieldRef.current.blur()
        _selected = 'none'
      }
      if (['Tab', 'ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(code)) {
        event.preventDefault()
        if (code === 'Tab' || code === 'ArrowRight') _selected = state.SELECTED_RANGE[state.selected].next
        if (code === 'ArrowLeft') _selected = state.SELECTED_RANGE[state.selected].previous
        if (code === 'ArrowUp') _time = bumpSelected({ direction: 'up', time: state.time, selected: state.selected })
        if (code === 'ArrowDown') _time = bumpSelected({ direction: 'down', time: state.time, selected: state.selected })
      }
      return {
        ...state,
        selected: _selected ?? state.selected,
        time: _time ?? state.time
      }
  
    case 'setSelected': 
      const { selected } = action
      return {
        ...state,
        selected
      }
  
    case 'setTime': 
      const { time } = action
      return {
        ...state,
        time
      }
  
    default:
      console.log(`reducer > no matching case for ${action.type}`)
  }
}
  
  
// Helper
const bumpSelected = ({ direction, time, selected }) => {
  let { hours, minutes, meridiem } = time
  if (selected === 'hours') {
    if (direction === 'up') {
      hours = hours === '12' ? ' 1' : String(Number(hours) + 1).padStart(2, ' ')
    } else {
      hours = hours === ' 1' ? '12' : String(Number(hours) - 1).padStart(2, ' ')
    }
  }
  
  if (selected === 'minutes') {
    if (direction === 'up') {
      minutes = minutes === '59' ? '00' : String(Number(minutes) + 1).padStart(2, '0')
    } else {
      minutes = minutes === '00' ? '59' : String(Number(minutes) - 1).padStart(2, '0')
    }
  }
  
  if (selected === 'meridiem') {
    meridiem = meridiem === 'AM' ? 'PM' : 'AM'
  }
  
  return { hours, minutes, meridiem }
}