import getFertilityStatus from 'sympto'
import cycleModule from './cycle'
import { useCervixObservable } from '../local-storage'
import { fertilityStatus as labels } from '../i18n/en/labels'

export function getFertilityStatusForDay(dateString) {
  const status = getCycleStatusForDay(dateString)
  if (!status) return {
    status: labels.fertile,
    phase: null,
    statusText: labels.unknown
  }

  const phases = Object.keys(status.phases)
  const phaseNameForDay = phases.find(phaseName => {
    const phase = status.phases[phaseName]
    const dayIsAfterPhaseStart = dateString >= phase.start.date
    let dayIsBeforePhaseEnd
    if (phase.end) {
      dayIsBeforePhaseEnd = dateString <= phase.end.date
    } else {
      dayIsBeforePhaseEnd = true
    }
    return dayIsAfterPhaseStart && dayIsBeforePhaseEnd
  })

  // if there's only cycle data for the pre phase and the target day is after its end,
  // the day is in the peri phase
  if (phases.length === 1 && phases[0] === 'preOvulatory' && !phaseNameForDay) {
    return formatStatus('periOvulatory', dateString, {phases: {periOvulatory: {}}})
  }

  return formatStatus(phaseNameForDay, dateString, status)
}

export function getCycleStatusForDay(dateString, opts = {}) {
  const {
    getCycleForDay,
    getCyclesBefore,
    getPreviousCycle
  } = cycleModule()

  const cycle = getCycleForDay(dateString)
  if (!cycle) return null

  const cycleInfo = {cycle: formatCycleForSympto(cycle)}

  const previousCycle = getPreviousCycle(dateString)

  if (previousCycle) {
    cycleInfo.previousCycle = formatCycleForSympto(previousCycle)
  }
  if (previousCycle && !opts.excludeEarlierCycles) {
    const earlierCycles = getCyclesBefore(previousCycle[0])
    if (earlierCycles) {
      cycleInfo.earlierCycles = earlierCycles.map(formatCycleForSympto)
    }
  }

  cycleInfo.secondarySymptom = useCervixObservable.value ? 'cervix' : 'mucus'

  return getFertilityStatus(cycleInfo)
}

function formatStatus(phaseNameForDay, dateString, status) {
  const mapping = {
    preOvulatory: () => {
      return {
        status: labels.infertile,
        phase: 1,
        statusText: labels.preOvuText
      }
    },
    periOvulatory: (dateString, status) => {
      //there might not actually be any data for the phase
      const peri = status.phases.periOvulatory
      const phaseEnd = peri && peri.end
      let s
      if (phaseEnd && phaseEnd.date === dateString) {
        s = labels.fertileUntilEvening
      } else {
        s = labels.fertile
      }
      return {
        status: s,
        phase: 2,
        statusText: labels.periOvuText
      }
    },
    postOvulatory: (dateString, status) => {
      return {
        status: labels.infertile,
        phase: 3,
        statusText: labels.postOvuText(status.temperatureShift.rule)
      }
    }
  }

  return mapping[phaseNameForDay](dateString, status)
}

function formatCycleForSympto(cycle) {
  const formatted = cycle.reduce((acc, oldDay) => {
    // deep clone
    const day = JSON.parse(JSON.stringify(oldDay));
    // remove excluded symptoms
    ['bleeding', 'temperature', 'mucus', 'cervix'].forEach(symptomName => {
      if (day[symptomName] && day[symptomName].exclude) {
        delete day[symptomName]
      }
    })
    // remove days with incomplete cervix values
    if (hasIncompleteCervixValue(day)) {
      delete day.cervix
    }
    // remove days with incomplete mucus value (because nfp-mucus returns null when that's the case)
    if (day.mucus && day.mucus.value === null) {
      delete day.mucus
    }
    // change format
    ['bleeding', 'temperature', 'mucus'].forEach(symptomName => {
      if (day[symptomName]) day[symptomName] = day[symptomName].value
    })
    acc.push(day)
    return acc
  }, [])
  // we get earliest last, but sympto wants earliest first
  formatted.reverse()
  return formatted
}

function hasIncompleteCervixValue(day) {
  return day.cervix && (typeof day.cervix.opening != 'number' || typeof day.cervix.firmness != 'number')
}