/* globals i18n */

import Component from 'ember-component';
import computed from 'ember-computed';
import injectService from 'ember-service/inject';
import moment from 'moment';
import run from 'ember-runloop';

import {
  WEEKS_RESOLUTION,
  MONTHS_RESOLUTION
} from 'web-client/components/dashboards/revenue/date-picker/component';

const API_DATE_FORMAT = 'YYYY-MM-DD';

const REV_COLOR = {
  ad: '#C5B6E2',
  sub: '#7753BA',
  tPrime: '#029CDC',
  bits: '#3CC6AE'
};

const SUB_COLOR = {
  total: '#7753BA',
  new: '#11B866',
  border: '#fff',
  tPrime: '#029CDC'
};

const SUB_REVENUE_LABEL = i18n('Sub Revenue');
const AD_REVENUE_LABEL = i18n('Ad Revenue');
const TPRIME_REVENUE_LABEL = i18n('Twitch Prime Revenue');
const BITS_REVENUE_LABEL = i18n('Bits Revenue');
const DAILY_SUBS_LABEL = i18n('Subs');
const TWITCH_PRIME_SUBS_LABEL = i18n('Twitch Prime Subs');

const FRACTION_KEY_FORMAT = {
  default: 'YYYY-MM-DD',
  weeks: 'YYYY-ww',
  months: 'YYYY-MM'
};

const FRACTION_LABEL_FORMAT = {
  default: 'ddd, MMM Do YYYY',
  weeks: 'MMM DD, YYYY',
  months: 'MMM YYYY'
};

export default Component.extend({
  api: injectService(),

  // Passed-in property:
  channelId: null,

  // Own properties:
  isGettingRevenueData: true,
  isGettingSubscriptionsData: true,

  startDate: null,
  endDate: null,
  resolution: null,

  fraction: computed('resolution', function () {
    return this.get('resolution') === MONTHS_RESOLUTION ? 'month' : 'day';
  }),

  fractionKeyFormat: computed('resolution', function () {
    return FRACTION_KEY_FORMAT[this.get('resolution')] || FRACTION_KEY_FORMAT.default;
  }),

  fractionLabelFormat: computed('resolution', function () {
    return FRACTION_LABEL_FORMAT[this.get('resolution')] || FRACTION_LABEL_FORMAT.default;
  }),

  // whitelist for bits
  isBitsOnboarded: false,

  // chart data
  revenueChartData: null,
  subscriptionsChartData: null,

  // calculated revenue numbers
  rangeSubRevenue: null,
  rangeAdRevenue: null,
  rangeTPrimeRevenue: null,
  rangeBitsRevenue: null,

  // calculated compare revenue numbers
  compareStartDate: null,
  compareEndDate: null,
  compareRangeSubRevenue: null,
  compareRangeAdRevenue: null,
  compareRangeTPrimeRevenue: null,
  compareRangeBitsRevenue: null,

  actions: {
    updateFilter(filter) {
      this.setProperties(filter);

      run.once(this, '_loadRevenueData');
      run.once(this, '_loadSubscriptionsData');
    }
  },

  // Functions to retrieve rev and sub data
  _loadRevenueData() {
    this.set('isGettingRevenueData', true);

    let channelId = this.get('channelId');
    let api = this.get('api');
    let url = `/api/channels/${ channelId }/revenue`;
    let startDate = moment(this.get('startDate')).locale('en');
    let endDate = moment(this.get('endDate')).add(1, 'day').locale('en');
    let endWeekDate = moment(endDate).endOf('week').add(1, 'day').locale('en');
    let resolution = this.get('resolution');
    let fraction = this.get('fraction');
    let diff;

    // adjust the diff to reflect an incomplete week
    if (resolution === WEEKS_RESOLUTION && !endDate.isSame(endWeekDate)) {
      diff = moment.range(startDate, endWeekDate).diff(resolution);
    } else {
      diff = moment.range(startDate, endDate).diff(resolution);
    }

    // set range we compare on
    this.set('compareStartDate', moment(startDate).subtract(diff, resolution));
    this.set('compareEndDate', moment(startDate).subtract(1, 'day'));

    startDate.subtract(diff, resolution);

    let filter = {
      start_date: startDate.format(API_DATE_FORMAT),
      end_date: endDate.format(API_DATE_FORMAT),
      fraction: fraction
    };

    api.request('get', url, filter).then(response => {
      if (this.isDestroyed) { return; }

      this.set('isBitsOnboarded', response.bits_onboarded);
      this._setRevenueData(response);
    }).finally(() => {
      if (this.isDestroyed) { return; }

      this.set('isGettingRevenueData', false);
    });
  },

  _loadSubscriptionsData() {
    this.set('isGettingSubscriptionsData', true);

    let channelId = this.get('channelId');
    let api = this.get('api');
    let url = `/api/channels/${ channelId }/subscriptions`;
    let startDate = moment(this.get('startDate')).locale('en');
    let endDate = moment(this.get('endDate')).add(1, 'day').locale('en');
    let fraction = this.get('fraction');
    let filter = {
      start_date: startDate.format(API_DATE_FORMAT),
      end_date: endDate.format(API_DATE_FORMAT),
      fraction: fraction
    };

    api.request('get', url, filter).then(response => {
      if (this.isDestroyed) { return; }

      this._setSubscriptionsData(response);
    }).finally(() => {
      if (this.isDestroyed) { return; }

      this.set('isGettingSubscriptionsData', false);
    });
  },

  // Compile and Calculate Data Functions
  _setRevenueData(revenueData) {
    let subDataPayload = revenueData.sub_data;
    let adDataPayload = revenueData.ad_data;
    let tPrimeDataPayload = revenueData.other_data;
    let bitsDataPayload = Array.isArray(revenueData.bits_data) ? revenueData.bits_data : [];

    // By Day
    let datasets = [];
    let adData = {};
    let subData = {};
    let tPrimeData = {};
    let bitsData = {};
    let labels = {};
    let totalAdRevenue = 0;
    let totalSubRevenue = 0;
    let totalTPrimeRevenue = 0;
    let totalBitsRevenue = 0;
    let totalAdRevenueComparison = 0;
    let totalSubRevenueComparison = 0;
    let totalTPrimeRevenueComparison = 0;
    let totalBitsRevenueComparison = 0;
    let resolution = this.get('resolution');
    let isWeekly = resolution === WEEKS_RESOLUTION;
    let keyDateFormat = this.get('fractionKeyFormat');
    let labelDateFormat = this.get('fractionLabelFormat');
    let startDate = moment(this.get('startDate'));
    let endDate = isWeekly ? moment(this.get('endDate')).endOf('week') : moment(this.get('endDate'));
    let currentDate = isWeekly ? startDate.endOf('week') : startDate;

    while (currentDate.isSameOrBefore(endDate)) {
      let formattedDate = currentDate.format(keyDateFormat);

      adData[formattedDate] = 0;
      subData[formattedDate] = 0;
      tPrimeData[formattedDate] = 0;
      bitsData[formattedDate] = 0;

      if (isWeekly) {
        let today = moment().endOf('day');
        let weekStart = moment(currentDate).startOf('week').format(labelDateFormat);
        let weekEnd = moment(moment.min(currentDate, today)).format(labelDateFormat);

        labels[formattedDate] = `${ weekStart } - ${ weekEnd }`;
      } else {
        labels[formattedDate] = currentDate.format(labelDateFormat);
      }

      currentDate.add(1, resolution);
    }

    subDataPayload.forEach(sub => {
      let recognizedOnDate = moment.utc(sub.recognized_on);
      let date = isWeekly ? recognizedOnDate.endOf('week') : recognizedOnDate;
      let formattedDate = date.format(keyDateFormat);
      let revenue = parseInt(sub.partner_revenue) / 100;

      if (revenue < 0) {
        revenue = 0;
      }

      if (typeof subData[formattedDate] === 'undefined') {
        totalSubRevenueComparison += revenue;
      } else {
        totalSubRevenue += revenue;
        subData[formattedDate] += revenue;
      }
    });

    adDataPayload.forEach(ad => {
      let reportDate = moment.utc(ad.report_date);
      let date = isWeekly ? reportDate.endOf('week') : reportDate;
      let formattedDate = date.format(keyDateFormat);
      let revenue = parseInt(ad.partner_revenue) / 100;

      if (revenue < 0) {
        revenue = 0;
      }

      if (typeof adData[formattedDate] === 'undefined') {
        totalAdRevenueComparison += revenue;
      } else {
        totalAdRevenue += revenue;
        adData[formattedDate] += revenue;
      }
    });

    tPrimeDataPayload.forEach(tPrime => {
      let tPrimeDate = moment.utc(tPrime.recognized_on);
      let date = isWeekly ? tPrimeDate.endOf('week') : tPrimeDate;
      let formattedDate = date.format(keyDateFormat);
      let revenue = parseInt(tPrime.partner_revenue) / 100;

      if (revenue < 0) {
        revenue = 0;
      }

      if (typeof tPrimeData[formattedDate] === 'undefined') {
        totalTPrimeRevenueComparison += revenue;
      } else {
        totalTPrimeRevenue += revenue;
        tPrimeData[formattedDate] += revenue;
      }
    });

    bitsDataPayload.forEach(bits => {
      let bitsDate = moment.utc(bits.date);
      let date = isWeekly ? bitsDate.endOf('week') : bitsDate;
      let formattedDate = date.format(keyDateFormat);
      let revenue = parseInt(bits.cents) / 100;

      if (revenue < 0) {
        revenue = 0;
      }

      if (typeof bitsData[formattedDate] === 'undefined') {
        totalBitsRevenueComparison += revenue;
      } else {
        totalBitsRevenue += revenue;
        bitsData[formattedDate] += revenue;
      }
    });

    datasets = [
      {
        label: SUB_REVENUE_LABEL,
        backgroundColor: REV_COLOR.sub,
        borderColor: REV_COLOR.sub,
        data: Object.keys(subData).map(key => subData[key])
      },
      {
        label: AD_REVENUE_LABEL,
        backgroundColor: REV_COLOR.ad,
        borderColor: REV_COLOR.ad,
        data: Object.keys(adData).map(key => adData[key])
      },
      {
        label: TPRIME_REVENUE_LABEL,
        backgroundColor: REV_COLOR.tPrime,
        borderColor: REV_COLOR.tPrime,
        data: Object.keys(tPrimeData).map(key => tPrimeData[key])
      }
    ];

    if (this.get('isBitsOnboarded')) {
      datasets.push({
        label: BITS_REVENUE_LABEL,
        backgroundColor: REV_COLOR.bits,
        borderColor: REV_COLOR.bits,
        data: Object.keys(bitsData).map(key => bitsData[key])
      });
    }

    let revenueChartData = {
      labels: Object.keys(labels).map(key => labels[key]),
      datasets: datasets
    };

    this.set('rangeSubRevenue', totalSubRevenue);
    this.set('rangeAdRevenue', totalAdRevenue);
    this.set('rangeTPrimeRevenue', totalTPrimeRevenue);
    this.set('rangeBitsRevenue', totalBitsRevenue);
    this.set('compareRangeSubRevenue', totalSubRevenueComparison);
    this.set('compareRangeAdRevenue', totalAdRevenueComparison);
    this.set('compareRangeTPrimeRevenue', totalTPrimeRevenueComparison);
    this.set('compareRangeBitsRevenue', totalBitsRevenueComparison);
    this.set('revenueChartData', revenueChartData);
  },

  _setSubscriptionsData(subscriptionsPayload) {
    let subData = {};
    let primeSubData = {};
    let labels = {};
    let resolution = this.get('resolution');
    let isWeekly = resolution === WEEKS_RESOLUTION;
    let keyDateFormat = this.get('fractionKeyFormat');
    let labelDateFormat = this.get('fractionLabelFormat');
    let startDate = moment(this.get('startDate'));
    let endDate = isWeekly ? moment(this.get('endDate')).endOf('week') : moment(this.get('endDate'));
    let currentDate = isWeekly ? startDate.endOf('week') : startDate;

    while (currentDate.isSameOrBefore(endDate)) {
      let date = currentDate.format(keyDateFormat);

      subData[date] = 0;
      primeSubData[date] = 0;


      if (isWeekly) {
        let today = moment().endOf('day');
        let weekStart = moment(currentDate).startOf('week').format(labelDateFormat);
        let weekEnd = moment(moment.min(currentDate, today)).format(labelDateFormat);

        labels[date] = `${ weekStart } - ${ weekEnd }`;
      } else {
        labels[date] = currentDate.format(labelDateFormat);
      }

      currentDate.add(1, resolution);
    }
    // Old data stream
    if (!subscriptionsPayload.twitch_subscriptions) {
      subscriptionsPayload.forEach(sub => {
        let subDate = moment.utc(sub.sub_date);
        let date = isWeekly ? subDate.endOf('week') : subDate;
        let formattedDate = date.format(keyDateFormat);
        let subCount = parseInt(sub.day_subscriptions);

        if (typeof subData[formattedDate] === 'undefined') { return; }

        subData[formattedDate] += subCount;
      });
    } else {
      subscriptionsPayload.twitch_subscriptions.forEach(sub => {
        let subDate = moment.utc(sub.sub_date);
        let date = isWeekly ? subDate.endOf('week') : subDate;
        let formattedDate = date.format(keyDateFormat);
        let subCount = parseInt(sub.day_subscriptions);

        if (typeof subData[formattedDate] === 'undefined') { return; }

        subData[formattedDate] += subCount;
      });

      subscriptionsPayload.prime_subscriptions.forEach(sub => {
        let subDate = moment.utc(sub.sub_date);
        let date = isWeekly ? subDate.endOf('week') : subDate;
        let formattedDate = date.format(keyDateFormat);
        let subCount = parseInt(sub.day_subscriptions);

        if (typeof primeSubData[formattedDate] === 'undefined') { return; }

        primeSubData[formattedDate] += subCount;
      });

    }

    let subscriptionsChartData = {
      labels: Object.keys(labels).map(key => labels[key]),
      datasets: [{
        label: DAILY_SUBS_LABEL,
        data: Object.keys(subData).map(key => subData[key]),
        fill: false,
        borderColor: SUB_COLOR.total,
        backgroundColor: SUB_COLOR.total,
        pointRadius: 5,
        pointBorderColor: SUB_COLOR.border,
        pointBackgroundColor: SUB_COLOR.total,
        pointBorderWidth: 2,
        pointHoverRadius: 10,
        pointHoverBorderWidth: 4,
        pointHoverBorderColor: SUB_COLOR.border
      },
      {
        label: TWITCH_PRIME_SUBS_LABEL,
        data: Object.keys(primeSubData).map(key => primeSubData[key]),
        fill: false,
        borderColor: SUB_COLOR.tPrime,
        backgroundColor: SUB_COLOR.tPrime,
        pointRadius: 5,
        pointBorderColor: SUB_COLOR.border,
        pointBackgroundColor: SUB_COLOR.tPrime,
        pointBorderWidth: 2,
        pointHoverRadius: 10,
        pointHoverBorderWidth: 4,
        pointHoverBorderColor: SUB_COLOR.border
      }]
    };

    this.set('subscriptionsChartData', subscriptionsChartData);
  }
});
