// @ts-ignore
import {
  toDate,
  addDays,
  addHours,
  addMinutes,
  getYear,
  getMonth,
  getDate,
  startOfDay,
  endOfDay,
  isBefore,
  isAfter,
  isWithinInterval,
  differenceInSeconds,
} from 'date-fns'

const isDST = function (d: Date) {
  const jan = new Date(d.getFullYear(), 0, 1).getTimezoneOffset()
  const jul = new Date(d.getFullYear(), 6, 1).getTimezoneOffset()
  return Math.max(jan, jul) !== d.getTimezoneOffset()
}

const dayCalc = (offsetDay = 0, offSetHour = 0, hijrioffset: any = 0, city = 'Europe/Dublin') => {
  const now = addHours(new Date(), offSetHour + offsetDay * 24)
  const month = getMonth(now)
  const date = getDate(now)

  const hijri = addDays(now, hijrioffset)
  const start = startOfDay(now)
  const end = endOfDay(now)

  const dstAdjust = isDST(now) ? 1 : 0

  return { now, month, date, start, end, hijri, dstAdjust }
}

const prayerCalc = (
  hourMinute: [number, number],
  hourMinuteNext: [number, number],
  index: number,
  now: Date,
  when: string,
  jamaahmethods: { [x: string]: string },
  jamaahoffsets: { [x: number]: number[] },
  dstAdjust: number
) => {
  const [hour, minute] = hourMinute
  const [hourNext, minuteNext] = hourMinuteNext

  let time = addHours(toDate(new Date(getYear(now), getMonth(now), getDate(now), hour, minute)), dstAdjust)

  /* *********************** */
  /* JAMAAH CALC             */
  /* *********************** */
  const hourOffset = jamaahoffsets[index][0]
  const minuteOffset = jamaahoffsets[index][1]
  const jamaahmethod = jamaahmethods[index]
  let jtime

  switch (jamaahmethod) {
    case 'afterthis':
      jtime = addMinutes(time, hourOffset * 60 + minuteOffset)
      break
    case 'fixed':
      jtime = toDate(new Date(getYear(now), getMonth(now), getDate(now), hourOffset, minuteOffset))

      break
    case 'beforenext':
      const rawjtime = toDate(new Date(getYear(now), getMonth(now), getDate(now), hourNext, minuteNext))

      jtime = addMinutes(rawjtime, -hourOffset * 60 - minuteOffset + dstAdjust * 60)
      break
    default:
      jtime = time
  }
  // if jtime before adhan / ie. summer time
  if (isBefore(jtime, time)) {
    time = jtime
  }

  /* *********************** */
  /* NAMES                   */
  /* *********************** */
  const names = ['fajr', 'shurooq', 'dhuhr', 'asr', 'maghrib', 'isha']
  const name = names[index]
  const hasPassed = isAfter(now, time)
  const isJamaahPending = isWithinInterval(now, { start: time, end: jtime })

  const isNext = false

  const result = { time, isJamaahPending, jtime, index, hasPassed, name, when, dstAdjust, isNext }
  return result
}

const prayersCalc = (
  timetable: any,
  settings: { hijrioffset: any, jamaahmethods: any, jamaahoffsets: any },
  showJamaah = true,
  city = 'Europe/Dublin'
) => {
  const { hijrioffset, jamaahmethods, jamaahoffsets } = settings
  const { now, month, date, start, hijri, dstAdjust } = dayCalc(0, 0, hijrioffset, city)
  const {
    now: nowYesterday,
    month: monthYesterday,
    date: dateYesterday,
    dstAdjust: dstAdjustYesterday,
  } = dayCalc(-1, 0, hijrioffset, city)
  const {
    now: nowTomorrow,
    month: monthTomorrow,
    date: dateTomorrow,
    dstAdjust: dstAdjustTomorrow,
  } = dayCalc(1, 0, hijrioffset, city)

  /* *********************** */
  /* SET PRAYERS             */
  /* *********************** */
  const prayersToday = timetable[month + 1][date].map((hourMinute: [number, number], index: number) => {
    const hourMinuteNext = index < 5 ? timetable[month + 1][date][index + 1] : [24, 0]
    return prayerCalc(hourMinute, hourMinuteNext, index, now, 'today', jamaahmethods, jamaahoffsets, dstAdjust)
  })

  const prayersYesterday = timetable[monthYesterday + 1][dateYesterday].map(
    (hourMinute: [number, number], index: number) => {
      const hourMinuteNext = index < 5 ? timetable[month + 1][date][index + 1] : [24, 0]
      return prayerCalc(
        hourMinute,
        hourMinuteNext,
        index,
        nowYesterday,
        'yesterday',
        jamaahmethods,
        jamaahoffsets,
        dstAdjustYesterday
      )
    }
  )
  const prayersTomorrow = timetable[monthTomorrow + 1][dateTomorrow].map((hourMinute: [any, any], index: number) => {
    const hourMinuteNext = index < 5 ? timetable[month + 1][date][index + 1] : [24, 0]
    return prayerCalc(
      hourMinute,
      hourMinuteNext,
      index,
      nowTomorrow,
      'tomorrow',
      jamaahmethods,
      jamaahoffsets,
      dstAdjustTomorrow
    )
  })

  /* *********************** */
  /* PREVIOUS, CURRENT, NEXT */
  /* *********************** */
  let current
  let next
  let previous

  if (isWithinInterval(now, { start, end: prayersToday[0].time })) {
    previous = prayersYesterday[4]
    current = prayersYesterday[5]
    next = prayersToday[0]
  } else if (isWithinInterval(now, { start: prayersToday[0].time, end: prayersToday[1].time })) {
    previous = prayersYesterday[5]
    current = prayersToday[0]
    next = prayersToday[1]
  } else if (isWithinInterval(now, { start: prayersToday[1].time, end: prayersToday[2].time })) {
    previous = prayersToday[0]
    current = prayersToday[1]
    next = prayersToday[2]
  } else if (isWithinInterval(now, { start: prayersToday[2].time, end: prayersToday[3].time })) {
    previous = prayersToday[1]
    current = prayersToday[2]
    next = prayersToday[3]
  } else if (isWithinInterval(now, { start: prayersToday[3].time, end: prayersToday[4].time })) {
    previous = prayersToday[2]
    current = prayersToday[3]
    next = prayersToday[4]
  } else if (isWithinInterval(now, { start: prayersToday[4].time, end: prayersToday[5].time })) {
    previous = prayersToday[3]
    current = prayersToday[4]
    next = prayersToday[5]
  } else {
    previous = prayersToday[4]
    current = prayersToday[5]
    next = prayersTomorrow[0]
  }

  /* *********************** */
  /* COUNTDOWN/UP            */
  /* *********************** */
  const countUp = {
    name:
      current.isJamaahPending || !showJamaah ? current.name : `${current.name}${current.index !== 1 ? ' jamaah' : ''}`,
    time: current.isJamaahPending || !showJamaah ? current.time : current.jtime,
    duration:
      current.isJamaahPending || !showJamaah
        ? differenceInSeconds(now, current.time)
        : differenceInSeconds(now, current.jtime),
  }
  const countDown = {
    name: current.isJamaahPending && showJamaah ? `${current.name}${current.index !== 1 ? ' jamaah' : ''}` : next.name,
    time: current.isJamaahPending && showJamaah ? current.jtime : next.time,
    duration:
      current.isJamaahPending && showJamaah
        ? differenceInSeconds(current.jtime, now) + 1
        : differenceInSeconds(next.time, now) + 1,
  }

  const totalDuration = countUp.duration + countDown.duration

  const percentageRaw = 10000 - (countDown.duration / totalDuration) * 10000
  const percentage = Math.floor(percentageRaw) / 100

  const isAfterIsha = isAfter(now, prayersToday[5].jtime)
  const isJamaahPending = isWithinInterval(now, { start: current.time, end: current.jtime })
  const focus = current.isJamaahPending ? current : next

  // focused prayer - add isNext
  if (isAfterIsha) {
    prayersTomorrow[focus.index].isNext = true
  } else {
    prayersToday[focus.index].isNext = true
  }

  // add day if after isha
  const trueNow = now
  const trueHijri = hijri
  const newNow = isAfterIsha ? addDays(now, 1) : now
  const newHijri = isAfterIsha ? addDays(hijri, 1) : hijri

  const result = {
    prayers: {
      today: prayersToday,
      yesterday: prayersYesterday,
      tomorrow: prayersTomorrow,
    },
    previous,
    current,
    next,
    countUp,
    countDown,
    now: newNow,
    hijri: newHijri,
    trueNow,
    trueHijri,
    percentage,
    isAfterIsha,
    isJamaahPending,
    focus,
  }
  return result
}

export { prayersCalc, dayCalc }
