import { DateTime, Interval } from 'luxon'
import { FluidType } from 'enum/fluid.enum'
import {
  TimeStep,
  TimePeriod,
  IDataload,
} from 'services/dataConsumptionContracts'

export function defineTimePeriod(
  referenceDate: DateTime,
  timeStep: TimeStep,
  index: number
): TimePeriod {
  let date: DateTime
  switch (timeStep) {
    case TimeStep.YEAR:
      date = referenceDate.set({
        month: 1,
        day: 1,
        hour: 0,
        minute: 0,
        second: 0,
        millisecond: 0,
      })
      return new TimePeriod(
        date.plus({ years: -5 * index - (5 - 1) }),
        date.plus({ years: -5 * index })
      )
    case TimeStep.MONTH:
      date = referenceDate.set({
        month: 12,
        day: 1,
        hour: 0,
        minute: 0,
        second: 0,
        millisecond: 0,
      })
      return new TimePeriod(
        date.plus({ months: -12 * index - (12 - 1) }),
        date.plus({ months: -12 * index })
      )
    case TimeStep.DAY:
      date = referenceDate
        .endOf('week')
        .set({ hour: 0, minute: 0, second: 0, millisecond: 0 })
      return new TimePeriod(
        date.plus({ days: -7 * index - (7 - 1) }),
        date.plus({ days: -7 * index })
      )
    case TimeStep.HOUR:
      date = referenceDate.set({
        hour: 23,
        minute: 0,
        second: 0,
        millisecond: 0,
      })
      return new TimePeriod(
        date.set({ hour: 0, minute: 0 }).plus({ days: -1 * index }),
        date.plus({ days: -1 * index })
      )
    case TimeStep.HALF_AN_HOUR:
      date = referenceDate.set({ hour: 23, minute: 30 })
      return new TimePeriod(
        date.set({ hour: 0, minute: 0 }).plus({ days: -1 * index }),
        date.plus({ days: -1 * index })
      )
    default:
      date = referenceDate
      return new TimePeriod(
        date.plus({ days: -7 * index - (7 - 1) }),
        date.plus({ days: -7 * index })
      )
  }
}

export function defineFirstStepDate(
  referenceDate: DateTime,
  timeStep: TimeStep,
  index: number
): DateTime {
  const period = defineTimePeriod(referenceDate, timeStep, index)
  return period.startDate
}

export function defineLastStepDate(
  referenceDate: DateTime,
  timeStep: TimeStep,
  index: number
): DateTime {
  const period = defineTimePeriod(referenceDate, timeStep, index)
  return period.endDate
}

export function compareStepDate(
  timeStep: TimeStep,
  date1: DateTime,
  date2: DateTime
): boolean {
  switch (timeStep) {
    case TimeStep.YEAR:
      return date1.year === date2.year
    case TimeStep.MONTH:
      return date1.year === date2.year && date1.month === date2.month
    case TimeStep.DAY:
      return (
        date1.year === date2.year &&
        date1.month === date2.month &&
        date1.day === date2.day
      )
    case TimeStep.HOUR:
      return (
        date1.year === date2.year &&
        date1.month === date2.month &&
        date1.day === date2.day &&
        date1.hour === date2.hour
      )
    case TimeStep.HALF_AN_HOUR:
      return (
        date1.year === date2.year &&
        date1.month === date2.month &&
        date1.day === date2.day &&
        date1.hour === date2.hour &&
        Math.abs(date1.minute - date2.minute) < 30
      )
    default:
      return false
  }
}

export function defineDetailedTimeStep(
  timeStep: TimeStep,
  fluidTypes: FluidType[]
): TimeStep {
  if (fluidTypes.length === 1) {
    switch (timeStep) {
      case TimeStep.YEAR:
        return TimeStep.MONTH
      case TimeStep.MONTH:
        return TimeStep.DAY
      case TimeStep.DAY:
        switch (fluidTypes[0]) {
          case FluidType.ELECTRICITY:
            return TimeStep.HALF_AN_HOUR
          case FluidType.WATER:
            return TimeStep.HOUR
          case FluidType.GAS:
            return TimeStep.HOUR
        }
      case TimeStep.HOUR:
        return TimeStep.HOUR
      case TimeStep.HALF_AN_HOUR:
        return TimeStep.HALF_AN_HOUR
      default:
        return timeStep
    }
  } else {
    switch (timeStep) {
      case TimeStep.YEAR:
        return TimeStep.MONTH
      case TimeStep.MONTH:
        return TimeStep.DAY
      default:
        return timeStep
    }
  }
}

export function formatDetailedDate(
  date: DateTime,
  timeStep: TimeStep
): DateTime {
  switch (timeStep) {
    case TimeStep.YEAR:
      return date
    case TimeStep.MONTH:
      return date.set({
        month: 1,
        day: 1,
        hour: 0,
        minute: 0,
        second: 0,
        millisecond: 0,
      })
    case TimeStep.DAY:
      return date.set({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 })
    case TimeStep.HOUR:
      return date.set({ hour: 0, minute: 0, second: 0, millisecond: 0 })
    case TimeStep.HALF_AN_HOUR:
      return date.set({ minute: 0, second: 0, millisecond: 0 })
    default:
      return date
  }
}

export function incrementDate(
  increment: number,
  initialdate: DateTime,
  timeStep: TimeStep
): { incrementIndex: number; incrementedDate: DateTime } {
  let incrementIndex = 0
  let incrementedDate: DateTime = initialdate
  switch (timeStep) {
    case TimeStep.YEAR:
      incrementedDate = initialdate.plus({ year: increment })
      incrementIndex =
        (DateTime.local().year - incrementedDate.year) % 5 === 0
          ? 1
          : (DateTime.local().year - incrementedDate.year - 4) % 5 === 0
          ? -1
          : 0
      break
    case TimeStep.MONTH:
      incrementedDate = initialdate.plus({ month: increment })
      incrementIndex = initialdate.year - incrementedDate.year
      break
    case TimeStep.DAY:
      incrementedDate = initialdate.plus({ day: increment })
      if (initialdate.weekday === 1 && incrementedDate.weekday === 7) {
        incrementIndex = 1
      } else if (initialdate.weekday === 7 && incrementedDate.weekday === 1) {
        incrementIndex = -1
      } else {
        incrementIndex = 0
      }
      break
    case TimeStep.HOUR:
      incrementedDate = initialdate.plus({ hour: increment })
      if (initialdate.hour === 0 && incrementedDate.hour === 23) {
        incrementIndex = 1
      } else if (initialdate.hour === 23 && incrementedDate.hour === 0) {
        incrementIndex = -1
      } else {
        incrementIndex = 0
      }
      break
    case TimeStep.HALF_AN_HOUR:
      incrementedDate = initialdate.plus({ minute: increment * 30 })
      if (initialdate.hour === 0 && incrementedDate.hour === 23) {
        incrementIndex = 1
      } else if (initialdate.hour === 23 && incrementedDate.hour === 0) {
        incrementIndex = -1
      } else {
        incrementIndex = 0
      }
      break
  }
  return { incrementIndex, incrementedDate }
}

export const isDataToCome = (dataload: IDataload, fluidType: FluidType) => {
  const inter =
    dataload &&
    Interval.fromDateTimes(dataload.date, DateTime.local()).count('days')
  if (fluidType === FluidType.ELECTRICITY && inter < 2) {
    return true
  }
  if (fluidType === FluidType.WATER && inter < 4) {
    return true
  }
  if (fluidType === FluidType.GAS && inter < 3) {
    return true
  } else {
    return false
  }
}