import numeral from 'numeral';
import ReactHighcharts from 'react-highcharts';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import dayTimezone from 'dayjs/plugin/timezone';

dayjs.extend(utc);
dayjs.extend(dayTimezone);

export function truncateNumber() {
  let number = parseFloat(this.value);

  if (number > 1000000) {
    number = numeral(number).format('0.[00]a');
  } else if (number >= 10000) {
    number = numeral(number).format('0.[0]a');
  } else if (number < 2 && number > 0) {
    number = numeral(number).format('0,0.0');
  } else {
    number = numeral(number).format('0,0');
  }

  return number;
}

export function xAxisLabelFormatter() {
  const date = dayjs(new Date(this.value)).utc();
  if (!date.isValid()) return this.value;
  const isFirstOfMonth = date.date() === 1;
  if (this.isFirst || isFirstOfMonth) {
    return date.format('MMM D');
  }
  return date.format('D');
}

export const getXAxis = () => ({
  gridLineWidth: 0,
  lineColor: '#F3F5F7',
  lineWidth: 2,
  maxPadding: 0,
  minPadding: 0,
  tickLength: 0,
  minorGridLineWidth: 0,
  title: { text: null },
  type: 'datetime',
  labels: {
    align: 'center',
    formatter: xAxisLabelFormatter,
    x: 0,
    y: 25,
    style: {
      'font-size': '0.875rem',
      'font-weight': '400',
      'font-family': 'Roboto, sans serif',
      'white-space': 'nowrap',
    },
  },
});

export const getYAxis = (stacked) => {
  const basicConfig = {
    title: { text: null },
    gridLineWidth: 2,
    max: null,
    min: 0,
    softMin: 0,
    minRange: 8,
    maxPadding: 0.1,
    minPadding: 0.1,
    gridLineColor: '#F3F5F7',
    lineColor: '#F3F5F7',
    showLastLabel: true,
    endOnTick: true,
    labels: {
      x: -15,
      y: 4,
      align: 'right',
      format: '{value}',
      formatter: truncateNumber,
      style: {
        'font-size': '0.875rem',
        'font-weight': '400',
        'font-family': 'Roboto, sans serif',
      },
    },
  }

  if (stacked){
    return [
      { ...basicConfig },
      { ...basicConfig },
      { ...basicConfig },
      { ...basicConfig },
    ];
  } else
  return [{...basicConfig},{...basicConfig}]
}

export const highChartsSeriesPrimaryConfig = (type = 'areaspline') => ({
  type: type,
  lineWidth: 3,
  states: {
    hover: {
      lineWidth: 3,
    },
  },
  data: null,
});

export const getMinorTickInterval = (dailyMetric) => {
  const oneDay = 24 * 3600 * 1000;
  const moreThanAMonth = dailyMetric.length > 31;

  return moreThanAMonth ?
    null :
    oneDay;
}

function reduceSeriesToValues(series) {
  let values = [];
  const reducedSeries = series.map(s => s.data.map(point => point.y));
  reducedSeries.forEach((s) => { values = values.concat(s); });
  return values;
}

function setChartLimits({ series, yAxis }, usesTwoScales) {
  if (!usesTwoScales) {
    const range = getSeriesRange(series);
    yAxis[0].floor = range.min;
    yAxis[0].ceiling = range.max;
  } else {
    const range = getSeriesRange([series[0]]);
    const secondaryRange = getSeriesRange([series[1]]);

    yAxis[0].floor = range.min;
    yAxis[0].ceiling = range.max;
    yAxis[1].floor = secondaryRange.min;
    yAxis[1].ceiling = secondaryRange.max;

    if (series[2]) {
      const thirdRange = getSeriesRange([series[2]]);
      yAxis[2].floor = thirdRange.min;
      yAxis[2].ceiling = thirdRange.max;
    }
  }
}

function getSeriesRange(series) {
  const reducedSeries = reduceSeriesToValues(series);
  let min = Math.min.apply(null, reducedSeries);
  let max = Math.max.apply(null, reducedSeries);
  const maxPaddingPercentage = 4.25;
  const minPaddingPercentage = 0.1;
  let topPaddingPercentage = (maxPaddingPercentage - Math.log10(max));
  if (topPaddingPercentage < minPaddingPercentage) {
    topPaddingPercentage = minPaddingPercentage;
  }
  let bottomPaddingPercentage = (maxPaddingPercentage - Math.log10(min));
  if (bottomPaddingPercentage < minPaddingPercentage) {
    bottomPaddingPercentage = minPaddingPercentage;
  }
  min -= (min / 100) * bottomPaddingPercentage;
  max += (max / 100) * topPaddingPercentage;
  return {
    min,
    max,
  };
}

const getScaleDifference = (secondarySeries, yAxisMax) => {
  let scaleDifference = 0;
  const secondaryYAxisMax = Math.max.apply(
    null,
    reduceSeriesToValues([secondarySeries])
  );
  if (secondarySeries) {
    if (yAxisMax > secondaryYAxisMax) {
      scaleDifference = Math.log10(yAxisMax) - Math.log10(secondaryYAxisMax);
    } else {
      scaleDifference = Math.log10(secondaryYAxisMax) - Math.log10(yAxisMax);
    }
  }
  return scaleDifference;
};

export const setYAxisScale = (
  [primarySeries, secondarySeries, ...otherSeries],
  xAxis,
  yAxis
) => {
  // we are using two scales only if there is a siginificative difference in scale
  const yAxisMax = Math.max.apply(null, reduceSeriesToValues([primarySeries]));
  let usesTwoScales = false;

  if (secondarySeries) {
    const scaleDifference = getScaleDifference(secondarySeries, yAxisMax);
    const maxScaleDifference = 0.7;

    if (scaleDifference >= maxScaleDifference && !xAxis.categories) {
      secondarySeries.yAxis = 1;
      yAxis[1].opposite = true;
      yAxis[1].offset = 30;
      yAxis[1].labels = Object.assign({}, yAxis[0].labels);
      yAxis[1].labels.x = 0;
      usesTwoScales = true;
    } else {
      secondarySeries.yAxis = 0;
    }
  }

  setChartLimits(
    {
      series: []
        .concat(primarySeries, secondarySeries, otherSeries)
        .filter(s => typeof s !== "undefined"),
      yAxis
    },
    usesTwoScales
  );
};

export const getMarkerFillColor = (color) => {
  const highchartColor = ReactHighcharts.Highcharts.Color(color);
  return highchartColor ?
    highchartColor.brighten(0.1).get('rgba') :
    color;
}

export const fadeColor = (color, opacity) => {
  const highchartColor = ReactHighcharts.Highcharts.Color(color);
  return highchartColor ?
    highchartColor.setOpacity(opacity).get('rgba') :
    color;
}

export const chartMargin = 24;

export default (tooltip = () => (null), stacked = false, type = 'areaspline', legend, height = 450) => {
  const config = {
    title: null,
    xAxis: getXAxis(),
    yAxis: getYAxis(stacked),
    chart: {
      spacingLeft: chartMargin,
      spacingRight: chartMargin,
      spacingTop: 40,
      height: height,
      type: type
    },
    legend: legend ? legend : {
      enabled: false,
    },
    credits: {
      enabled: false,
    },
    plotOptions: {
      areaspline: {
        stacking: stacked ? 'normal' : ''
      },
      series: {
        marker: {
          enabled: false,
          lineWidth: 3,
          radius: 3,
          symbol: "circle"
        },
        states: {
          hover: {
            radiusPlus: 1.5
          }
        }
      },
      column: {
        colorByPoint: stacked ? false : true,
        stacking: stacked ? 'normal' : ''
      }
    },
    tooltip: tooltip,
    series: []
  };

  return config;
};
