import { Client } from 'cozy-client'
import _ from 'lodash'
import { DateTime } from 'luxon'
import { FluidType } from 'enum/fluid.enum'
import { getPercentage, sum } from 'utils/math'
import { getDoctype } from 'utils/utils'

export type ProcessedData = {
  consumptionValue: number
  weeklyCompareValue: number
  euclideanComparator: string
}

export default class FluidService {
  public client: Client
  constructor(client: Client) {
    this.client = client
  }

  private getTimeQueryPredicate(
    startingdateTime: DateTime,
    endingdateTime: DateTime
  ) {
    return {
      year: {
        $lte: Math.max(startingdateTime.year, endingdateTime.year),
        $gte: Math.min(startingdateTime.year, endingdateTime.year),
      },
      month: {
        $lte: Math.max(startingdateTime.month, endingdateTime.month),
        $gte: Math.min(startingdateTime.month, endingdateTime.month),
      },
      day: {
        $lte: Math.max(startingdateTime.day, endingdateTime.day),
        $gte: Math.min(startingdateTime.day, endingdateTime.day),
      },
    }
  }

  /**
   * Query last 2 week data for grdf energy data
   */
  public getLastTwoWeeks(fluid: FluidType) {
    //const now = DateTime.local(2018, 4, 1)
    const now = DateTime.local()
    const twoWeekBefore = now.minus({
      week: 2,
    })
    return this.client.query(
      this.getClientQuery(
        getDoctype(fluid),
        now,
        twoWeekBefore,
        ['year', 'month', 'day'],
        14
      )
    )
  }

  /**
   * Build client query
   * @param doctype doctype name
   * @param startingTime start date for query
   * @param endingTime end date for query
   * @param indexFields fields needed to be indexed
   * @param recordsNumber number or return values
   */
  private getClientQuery(
    doctype: string,
    startingTime: DateTime,
    endingTime: DateTime,
    indexFields: string[],
    recordsNumber: number
  ) {
    return this.client
      .find(doctype)
      .where(this.getTimeQueryPredicate(startingTime, endingTime))
      .indexFields(indexFields)
      .limitBy(recordsNumber)
  }

  /**
   * Wrap up data needed for electrical indicators
   * @param {array} toBeProcessedData
   * @return {object} {consumptionValue: number, weeklyCompareValue: number, euclideanComparator: string}
   */
  public processElectricityData(toBeProcessedData: []) {
    const consumptionValue = sum(
      _.slice(_.map(toBeProcessedData, 'load'), 7, 14)
    )
    const weeklyCompareValue = getPercentage(
      _.slice(_.map(toBeProcessedData, 'load'), 7, 14),
      _.slice(_.map(toBeProcessedData, 'load'), 0, 7)
    )

    const euclideanComparator = this.getRelevantMetric(
      FluidType.ELECTRICITY,
      consumptionValue
    )
    return {
      consumptionValue: consumptionValue,
      weeklyCompareValue: weeklyCompareValue,
      euclideanComparator: euclideanComparator,
    }
  }

  /**
   * Wrap up data needed for gas indicators
   * @param {array} toBeProcessedData
   * @return {object} {consumptionValue: number, weeklyCompareValue: number, euclideanComparator: string}
   */
  public processGasData(toBeProcessedData: []) {
    // Remove last element in order to have pair number of value.
    toBeProcessedData.pop()
    const consumptionValue = sum(
      _.slice(_.map(toBeProcessedData, 'load'), 0, 7)
    )
    const weeklyCompareValue = getPercentage(
      _.slice(_.map(toBeProcessedData, 'load'), 0, 7),
      _.slice(_.map(toBeProcessedData, 'load'), 7, 14)
    )
    const euclideanComparator = this.getRelevantMetric(
      FluidType.GAS,
      consumptionValue
    )
    return {
      consumptionValue: consumptionValue,
      weeklyCompareValue: weeklyCompareValue,
      euclideanComparator: euclideanComparator,
    }
  }
  /**
   * Wrap up data needed for water indicators
   * @param {array} toBeProcessedData
   * @return {object} {consumptionValue: number, weeklyCompareValue: number, euclideanComparator: string}
   */
  public processWaterData(toBeProcessedData: []) {
    const consumptionValue = sum(
      _.slice(_.map(toBeProcessedData, 'load'), 0, 7)
    )
    const weeklyCompareValue = getPercentage(
      _.slice(_.map(toBeProcessedData, 'load'), 0, 7),
      _.slice(_.map(toBeProcessedData, 'load'), 7, 14)
    )
    const euclideanComparator = this.getRelevantMetric(
      FluidType.WATER,
      consumptionValue
    )
    return {
      consumptionValue: consumptionValue,
      weeklyCompareValue: weeklyCompareValue,
      euclideanComparator: euclideanComparator,
    }
  }

  /**
   * Return a relevant metric string according to a fluid type and a value
   * @param {FluidType} fluid
   * @param {number} value
   * @return {string} relevantValue
   */
  public getRelevantMetric(fluid: FluidType, value: number) {
    //TODO: When data is ready get it from db or locales
    switch (fluid) {
      case FluidType.ELECTRICITY:
        if (value > 100) {
          return "Vous avez consommé un max d'ampoules !"
        } else {
          return 'Une console de jeu fonctionnant 2 h par jour consomme 1,75 kWh en 1 semaine'
        }
      case FluidType.GAS:
        return 'Ca fait pas un peu trop de gas'
      case FluidType.WATER:
        return '3 piscines du rhône'
      default:
        return 'Pas de comparaison trouvée'
    }
  }
}