import { MetricsReporting, Optional } from 'backend-api/models';
import { MetricsReportingType } from 'backend-api/types';
import {
  AVERAGE_METRICS,
  CURRENCY_METRICS,
  DSP_REPORTING_METRICS,
  ESTIMATED_REVENUE_METRICS,
  FOLLOWERS_REPORTING_METRICS,
  GLOBAL_TERRITORY_ID,
  NON_CUMULATIVE_METRICS,
  STREAMS_REPORTING_METRICS,
  USD_CURRENCY_CODE,
} from 'common/constants';
import { MetricId, MetricSeries } from 'common/types';
import { meanBy, mergeWith } from 'lodash';
import { formatNumeral, formatShortenNumeral, getCurrencyFormatted } from 'utils/format';
import { isDateBetweenDaysInclusive } from 'common-v2/utils';

export const getReportingMetricType = (id: MetricId): Optional<MetricsReportingType> => {
  if (STREAMS_REPORTING_METRICS.includes(id)) return MetricsReportingType.STREAMS;
  if (FOLLOWERS_REPORTING_METRICS.includes(id)) return MetricsReportingType.FOLLOWERS;
  if (DSP_REPORTING_METRICS.includes(id)) return MetricsReportingType.DSP_METRICS;
  return;
};

export const mergeReportingMetrics = (current: MetricsReporting[], next: MetricsReporting[]): MetricsReporting[] =>
  current.map((c, i) => {
    return mergeWith(c, next[i], (newValue, currentValue) => (newValue !== null ? newValue : currentValue));
  });

export const isAverageMetric = (targetMetric: MetricId): boolean => AVERAGE_METRICS.includes(targetMetric);

export const isCurrencyMetric = (targetMetric: MetricId): boolean => CURRENCY_METRICS.includes(targetMetric);

export const isNonCumulativeMetric = (targetMetric: MetricId): boolean => NON_CUMULATIVE_METRICS.includes(targetMetric);

export const getFormattedTotalValue = (metricSeries: MetricSeries, currencyCode?: string): string => {
  if (metricSeries.data.length === 0) return 'N/A';

  let value: number;
  if (isNonCumulativeMetric(metricSeries.key)) {
    value = metricSeries.data[metricSeries.data.length - 1].value;
  } else if (isAverageMetric(metricSeries.key)) {
    value = meanBy(metricSeries.data, item => item.value);
  } else {
    value = metricSeries.data.reduce((res, item) => res + item.value, 0);
  }

  if (isCurrencyMetric(metricSeries.key)) {
    return getCurrencyFormatted(value, currencyCode);
  }

  return formatNumeral(value);
};

export const getFormattedPeriodTotalMetrics = (
  metricSeries: MetricSeries,
  startDate: Date,
  endDate: Date,
  currencyCode?: string
): string => {
  const metricSeriesWithinPeriod: MetricSeries = {
    ...metricSeries,
    data: metricSeries.data.filter(item => isDateBetweenDaysInclusive(item.date, startDate, endDate)),
  };

  return getFormattedTotalValue(metricSeriesWithinPeriod, currencyCode);
};

export const getDisabledMetricsForSelector = (
  otherMetric: MetricId,
  territoryId: number,
  projectCurrency?: string
): MetricId[] => {
  const disabledMetrics = [otherMetric];

  if (territoryId !== GLOBAL_TERRITORY_ID) {
    disabledMetrics.push(...FOLLOWERS_REPORTING_METRICS);
  }

  if (projectCurrency && projectCurrency !== USD_CURRENCY_CODE) {
    disabledMetrics.push(...ESTIMATED_REVENUE_METRICS);
  }

  return disabledMetrics;
};

export const isMetricForCountryInvalid = (metric: MetricId, territoryId: number) =>
  FOLLOWERS_REPORTING_METRICS.includes(metric) && territoryId !== GLOBAL_TERRITORY_ID;

export const isMetricInvalid = (metric: MetricId, territoryId: number, projectCurrency?: string) =>
  isMetricForCountryInvalid(metric, territoryId) ||
  (ESTIMATED_REVENUE_METRICS.includes(metric) && projectCurrency !== USD_CURRENCY_CODE);

export const getFormattedMetric = (value: number, metricSeries: MetricSeries, currencyCode?: string): string => {
  if (isCurrencyMetric(metricSeries.key)) {
    return getCurrencyFormatted(value, currencyCode);
  }

  return formatShortenNumeral(value);
};

export const getFormattedReportingMetricName = (metric: MetricSeries, currencyCode: Optional<string>): string => {
  if (!isCurrencyMetric(metric.key) || !currencyCode) {
    return metric.name;
  }

  return `${metric.name} (${currencyCode})`;
};
