<template>
  <highcharts :options="chartOptions" />
</template>

<script>
import Highcharts from 'highcharts';
import { Chart } from 'highcharts-vue';

export default {
  components: {
    highcharts: Chart,
  },
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    colors: {
      type: Array,
      default: () => [],
    },
    type: {
      type: String,
      default: '',
    },
    timeScale: {
      type: String,
      default: null,
    },
    warning: {
      type: Number,
      default: null,
    },
    critical: {
      type: Number,
      default: null,
    },
    max: {
      type: Number,
      default: null,
    },
    float: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    readyData() {
      let filteredData = this.data.map((metric) => {
        return {
          ...metric,
          Value: metric.Value === 'nan' ? 0 : metric.Value,
        };
      });

      filteredData.sort((a, b) => {
        return new Date(a.Timestamp) - new Date(b.Timestamp);
      });

      let transform = filteredData.map((metric) => {
        let date = new Date(metric.Timestamp);
        let time =
          date.getHours() + ':' + String(date.getMinutes()).padStart(2, '0');
        return {
          ...metric,
          Timestamp: time,
          Value: this.float ? metric.Value : Math.round(metric.Value),
        };
      });

      return transform;
    },

    step() {
      return this.timeScale === 'hour' ? 10 : 60;
    },

    metricData() {
      let group = this.readyData.reduce(function (rv, x) {
        (rv[x['Sensor']] = rv[x['Sensor']] || []).push(x);
        return rv;
      }, {});

      let metricArr = Object.keys(group).map((key, index) => {
        let groupTime = group[key].reduce(function (rv, x) {
          (rv[x['Timestamp']] = rv[x['Timestamp']] || []).push(x);
          return rv;
        }, {});

        let arr = Object.keys(groupTime).map((key) => {
          const findAverage = (arr) => {
            const { length } = arr;
            return Math.round(
              arr.reduce((acc, val) => {
                return acc + val.Value / length;
              }, 0)
            );
          };
          return findAverage(groupTime[key]);
        });

        return {
          name: key,
          data: arr,
          color: this.colors[index],
        };
      });
      return metricArr.length > 0
        ? metricArr
        : [
            { color: '', data: [], name: '' },
            { color: '', data: [], name: '' },
          ];
    },

    metricTime() {
      let timeGroup = this.readyData.reduce(function (rv, x) {
        (rv[x['Timestamp']] = rv[x['Timestamp']] || []).push(x);
        return rv;
      }, {});

      let timeArr = Object.keys(timeGroup);

      return timeArr;
    },

    chartOptions() {
      return {
        chart: {
          type: 'spline',
          margin: [52, 50, 32, 60],
          height: '360px',
          zoomType: 'xy',
          animation: true,
          resetZoomButton: {
            position: {
              x: 0,
              y: -50,
            },
          },
        },
        title: null,
        xAxis: {
          categories: this.metricTime,
          title: null,
          labels: {
            step: this.step,
          },
          minorGridLineColor: '#1A3E5B1A',
        },
        yAxis: {
          categories: this.categories,
          min: 0,
          max: this.yMax,
          title: null,
          minRange: this.minRange,
          minTickInterval: this.minTickInterval,
          minorGridLineColor: '#1A3E5B1A',
          plotLines: this.plotLines,
          plotBands: this.plotBands,
        },
        series: this.metricData.map((item) => ({
          ...item,
          marker: {
            enabled: false,
          },
        })),
        legend: {
          enabled: false,
        },
        tooltip: {
          enabled: false,
          crosshairs: false,
        },
        plotOptions: {
          series: {
            showInLegend: true,
          },
        },
      };
    },

    plotLines() {
      let plotLines = [
        {
          color: '#F0AC0C',
          dashStyle: 'solid',
          value: this.warning,
          zIndex: '1000',
          width: 2,
        },
      ];

      switch (this.type) {
        case 'fans':
        case 'processors':
        case 'power':
        case 'memory':
        case 'voltage-input':
        case 'voltage-output':
        case 'current':
        case 'psu-power':
          plotLines.push({
            color: '#E11717',
            dashStyle: 'solid',
            value: this.critical,
            width: 2,
            zIndex: 1,
            label: {
              text: this.$t('chart.thresholdFailure'),
              align: 'right',
              style: {
                fontFamily: 'Inter',
                fontSize: '12px',
                fontStyle: 'normal',
                fontWeight: '400',
                lineHeight: '16px',
                color: '#0C1C2999',
              },
            },
          });
          break;
      }
      return plotLines;
    },

    plotBands() {
      let plotBands = null;

      switch (this.type) {
        case 'motherboard':
          plotBands = [
            {
              color: '#F0AC0C1A',
              dashStyle: 'solid',
              from: this.warning,
              to: Infinity,
            },
          ];
          break;
        case 'memory':
        case 'processors':
        case 'power':
        case 'fans':
        case 'voltage-input':
        case 'voltage-output':
        case 'current':
        case 'psu-power':
          plotBands = [
            {
              color: '#F0AC0C1A',
              dashStyle: 'solid',
              from: this.warning,
              to: this.critical,
            },
            {
              color: '#FF41411A',
              dashStyle: 'solid',
              from: this.critical,
              to: Infinity,
            },
          ];
          break;
      }
      return plotBands;
    },

    yMax() {
      let yMax = null;

      switch (this.type) {
        case 'motherboard':
        case 'memory':
        case 'processors':
        case 'fans':
        case 'voltage-input':
        case 'voltage-output':
        case 'current':
        case 'psu-power':
          yMax = this.max;
          break;
        case 'power':
          yMax = 100;
          break;
      }
      return yMax;
    },

    categories() {
      let categories = null;

      switch (this.type) {
        case 'motherboard':
        case 'memory':
        case 'processors':
          categories = this.setCategories(this.setMaxWithInterval(), 'С°');
          break;
        case 'fans':
          categories = this.setSpeed(this.setMaxWithInterval());
          break;
        case 'power':
          categories = this.setCategories(101, 'Вт');
          break;
        case 'voltage-input':
        case 'voltage-output':
          categories = this.setCategories(this.setMaxWithInterval(), 'В');
          break;
        case 'current':
          categories = this.setCategories(11, 'A');
          break;
        case 'psu-power':
          categories = this.setCategories(126, 'Вт');
          break;
      }
      return categories;
    },

    minRange() {
      let minRange = null;

      switch (this.type) {
        case 'fans':
          minRange = 10000;
          break;
      }
      return minRange;
    },

    minTickInterval() {
      let minTickInterval = null;

      switch (this.type) {
        case 'fans':
          minTickInterval = 1000;
          break;
        case 'motherboard':
        case 'memory':
        case 'processors':
        case 'power':
        case 'voltage-input':
        case 'voltage-output':
        case 'current':
        case 'psu-power':
          minTickInterval = 25;
          break;
      }
      return minTickInterval;
    },
  },

  async created() {
    this.setOptions();
  },

  methods: {
    setOptions() {
      Highcharts.setOptions({
        lang: {
          resetZoom: this.$t('chart.resetZoom'),
        },
      });
    },
    setCategories(count, desc) {
      const arr = [...new Array(count)].map((i, k) => `${k} ${desc}`);
      return arr;
    },
    setSpeed(count) {
      const arr = [...new Array(count)].map((i, k) => `${k}`);
      return arr;
    },
    setMaxWithInterval() {
      return (
        Math.ceil(this.max / this.minTickInterval) * this.minTickInterval + 1
      );
    },
  },
};
</script>
