'use strict';

/**
 * Dependencies
 */
const toCamelCase = require('../helpers/to-camel-case');
const deepClone = require('../helpers/deep-clone');

/**
 * Options
 */
const AggregatedByOptions = ['day', 'week', 'month'];
const CountryOptions = ['us', 'ca'];
const SortByDirection = ['desc', 'asc'];

/**
 * Statistics class
 */
class Statistics {
  constructor(data) {
    this.startDate = null;
    this.endDate = null;
    this.aggregatedBy = null;

    if (data) {
      this.fromData(data);
    }
  }

  /**
   * Build from data
   */
  fromData(data) {

    //Expecting object
    if (typeof data !== 'object') {
      throw new Error('Expecting object for Statistics data');
    }

    //Convert to camel case to make it workable, making a copy to prevent
    //changes to the original objects
    data = deepClone(data);
    data = toCamelCase(data, ['substitutions', 'customArgs']);

    const { startDate,
      endDate,
      aggregatedBy,
    } = data;

    this.setStartDate(startDate);
    this.setEndDate(endDate);
    this.setAggregatedBy(aggregatedBy);
  }

  /**
   * Set startDate
   */
  setStartDate(startDate) {
    if (typeof startDate === 'undefined') {
      throw new Error('Date expected for `startDate`');
    }

    if ((new Date(startDate) === 'Invalid Date') ||
        isNaN(new Date(startDate))) {
      throw new Error('Date expected for `startDate`');
    }

    console.log(startDate);

    this.startDate = new Date(startDate).toISOString().slice(0, 10);
  }

  /**
   * Set endDate
   */
  setEndDate(endDate) {
    if (typeof endDate === 'undefined') {
      this.endDate = new Date().toISOString().slice(0, 10);
      return;
    }

    if (new Date(endDate) === 'Invalid Date' || isNaN(new Date(endDate))) {
      throw new Error('Date expected for `endDate`');
    }

    this.endDate = new Date(endDate).toISOString().slice(0, 10);
  }

  /**
   * Set aggregatedBy
   */
  setAggregatedBy(aggregatedBy) {
    if (typeof aggregatedBy === 'undefined') {
      return;
    }

    if (typeof aggregatedBy === 'string' &&
        AggregatedByOptions.includes(aggregatedBy.toLowerCase())) {
      this.aggregatedBy = aggregatedBy;
    } else {
      throw new Error('Incorrect value for `aggregatedBy`');
    }
  }

  /**
   * Get Global
   */
  getGlobal() {
    const { startDate, endDate, aggregatedBy } = this;

    return { startDate, endDate, aggregatedBy };
  }

  /**
   * Get Advanced
   */
  getAdvanced(country) {
    const json = this.getGlobal();

    if (typeof country === 'undefined') {
      return json;
    }

    if (typeof country === 'string' &&
        CountryOptions.includes(country.toLowerCase())) {
      json.country = country;
    }

    return json;
  }

  /**
   * Get Advanced Mailbox Providers
   */
  getAdvancedMailboxProviders(mailBoxProviders) {
    const json = this.getGlobal();

    if (typeof mailBoxProviders === 'undefined') {
      return json;
    }

    if (Array.isArray(mailBoxProviders) &&
        mailBoxProviders.some(x => typeof x !== 'string')) {
      throw new Error('Array of strings expected for `mailboxProviders`');
    }

    json.mailBoxProviders = mailBoxProviders;

    return json;
  }

  /**
   * Get Advanced Browsers
   */
  getAdvancedBrowsers(browsers) {
    const json = this.getGlobal();

    if (typeof browsers === 'undefined') {
      return json;
    }

    if (Array.isArray(browsers) && browsers.some(x => typeof x !== 'string')) {
      throw new Error('Array of strings expected for `browsers`');
    }

    json.browsers = browsers;

    return json;
  }

  /**
   * Get Categories
   */
  getCategories(categories) {
    if (typeof categories === 'undefined') {
      throw new Error('Array of strings expected for `categories`');
    }

    if (!this._isValidArrayOfStrings(categories)) {
      throw new Error('Array of strings expected for `categories`');
    }

    const json = this.getGlobal();
    json.categories = categories;

    return json;
  }

  /**
   * Get Subuser
   */
  getSubuser(subusers) {
    if (typeof subusers === 'undefined') {
      throw new Error('Array of strings expected for `subusers`');
    }

    if (!this._isValidArrayOfStrings(subusers)) {
      throw new Error('Array of strings expected for `subusers`');
    }

    const json = this.getGlobal();
    json.subusers = subusers;

    return json;
  }

  /**
   * Get Subuser Sum
   */
  getSubuserSum(sortByMetric = 'delivered',
    sortByDirection = SortByDirection[0], limit = 5, offset = 0) {
    if (typeof sortByMetric !== 'string') {
      throw new Error('string expected for `sortByMetric`');
    }

    if (!SortByDirection.includes(sortByDirection.toLowerCase())) {
      throw new Error('desc or asc expected for `sortByDirection`');
    }

    if (typeof limit !== 'number') {
      throw new Error('number expected for `limit`');
    }

    if (typeof offset !== 'number') {
      throw new Error('number expected for `offset`');
    }

    const json = this.getGlobal();

    json.sortByMetric = sortByMetric;
    json.sortByDirection = sortByDirection;
    json.limit = limit;
    json.offset = offset;

    return json;
  }

  /**
   * Get Subuser Monthly
   */
  getSubuserMonthly(sortByMetric = 'delivered',
    sortByDirection = SortByDirection[0], limit = 5, offset = 0) {
    if (typeof sortByMetric !== 'string') {
      throw new Error('string expected for `sortByMetric`');
    }

    if (!SortByDirection.includes(sortByDirection.toLowerCase())) {
      throw new Error('desc or asc expected for `sortByDirection`');
    }

    if (typeof limit !== 'number') {
      throw new Error('number expected for `limit`');
    }

    if (typeof offset !== 'number') {
      throw new Error('number expected for `offset`');
    }

    const json = this.getGlobal();

    json.sortByMetric = sortByMetric;
    json.sortByDirection = sortByDirection;
    json.limit = limit;
    json.offset = offset;

    return json;
  }

  _isValidArrayOfStrings(arr) {
    if (!Array.isArray(arr)) {
      return false;
    }

    if (arr.length < 1 || arr.some(x => typeof x !== 'string')) {
      return false;
    }

    return true;
  }
}

//Export class
module.exports = Statistics;
