<template>
  <LoadingCard :loading="loading" class="px-6 py-4">
    <div class="h-6 flex items-center mb-4">
      <h3 class="mr-3 leading-tight text-sm font-bold">{{ title }}</h3>

      <HelpTextTooltip :text="helpText" :width="helpWidth" />

      <SelectControl
        v-if="ranges.length > 0"
        class="ml-auto w-[6rem] shrink-0"
        size="xxs"
        :options="ranges"
        :selected="selectedRangeKey"
        @change="handleChange"
        :aria-label="__('Select Ranges')"
      />
    </div>

    <p class="flex items-center text-4xl mb-4">
      {{ formattedValue }}
      <span v-if="suffix" class="ml-2 text-sm font-bold">{{
        formattedSuffix
      }}</span>
    </p>

    <div
      ref="chart"
      class="absolute inset-0 rounded-b-lg ct-chart"
      style="top: 60%"
    />
  </LoadingCard>
</template>

<script>
import debounce from 'lodash/debounce'
import Chartist from 'chartist'
import 'chartist/dist/chartist.min.css'
import { singularOrPlural } from '@/util'
import ChartistTooltip from 'chartist-plugin-tooltips-updated'
import 'chartist-plugin-tooltips-updated/dist/chartist-plugin-tooltip.css'

export default {
  name: 'BaseTrendMetric',

  emits: ['selected'],

  props: {
    loading: Boolean,
    title: {},
    helpText: {},
    helpWidth: {},
    value: {},
    chartData: {},
    maxWidth: {},
    prefix: '',
    suffix: '',
    suffixInflection: { type: Boolean, default: true },
    ranges: { type: Array, default: () => [] },
    selectedRangeKey: [String, Number],
    format: {
      type: String,
      default: '0[.]00a',
    },
  },

  data: () => ({
    chartist: null,
    resizeObserver: null,
  }),

  watch: {
    selectedRangeKey: function (newRange, oldRange) {
      this.renderChart()
    },

    chartData: function (newData, oldData) {
      this.renderChart()
    },
  },

  created() {
    const debouncer = debounce(callback => callback(), Nova.config('debounce'))

    this.resizeObserver = new ResizeObserver(entries => {
      debouncer(() => {
        this.renderChart()
      })
    })
  },

  mounted() {
    const low = Math.min(...this.chartData)
    const high = Math.max(...this.chartData)

    // Use zero as the graph base if the lowest value is greater than or equal to zero.
    // This avoids the awkward situation where the chart doesn't appear filled in.
    const areaBase = low >= 0 ? 0 : low

    this.chartist = new Chartist.Line(this.$refs.chart, this.chartData, {
      lineSmooth: Chartist.Interpolation.none(),
      fullWidth: true,
      showPoint: true,
      showLine: true,
      showArea: true,
      chartPadding: {
        top: 10,
        right: 0,
        bottom: 0,
        left: 0,
      },
      low,
      high,
      areaBase,
      axisX: {
        showGrid: false,
        showLabel: true,
        offset: 0,
      },
      axisY: {
        showGrid: false,
        showLabel: true,
        offset: 0,
      },
      plugins: [
        ChartistTooltip({
          pointClass: 'ct-point',
          anchorToPoint: false,
        }),
        ChartistTooltip({
          pointClass: 'ct-point__left',
          anchorToPoint: false,
          tooltipOffset: {
            x: 50,
            y: -20,
          },
        }),
        ChartistTooltip({
          pointClass: 'ct-point__right',
          anchorToPoint: false,
          tooltipOffset: {
            x: -50,
            y: -20,
          },
        }),
      ],
    })

    this.chartist.on('draw', data => {
      if (data.type === 'point') {
        data.element.attr({
          'ct:value': this.transformTooltipText(data.value.y),
        })

        data.element.addClass(
          this.transformTooltipClass(data.axisX.ticks.length, data.index) ?? ''
        )
      }
    })

    this.resizeObserver.observe(this.$refs.chart)
  },

  beforeUnmount() {
    this.resizeObserver.unobserve(this.$refs.chart)
  },

  methods: {
    renderChart() {
      this.chartist.update(this.chartData)
    },

    handleChange(event) {
      const value = event?.target?.value || event

      this.$emit('selected', value)
    },

    transformTooltipText(value) {
      let formattedValue = Nova.formatNumber(new String(value), this.format)

      if (this.prefix) {
        return `${this.prefix}${formattedValue}`
      }

      if (this.suffix) {
        const suffix = this.suffixInflection
          ? singularOrPlural(value, this.suffix)
          : this.suffix

        return `${formattedValue} ${suffix}`
      }

      return `${formattedValue}`
    },

    transformTooltipClass(total, index) {
      if (index < 2) {
        return 'ct-point__left'
      } else if (index > total - 3) {
        return 'ct-point__right'
      }

      return 'ct-point'
    },
  },

  computed: {
    isNullValue() {
      return this.value == null
    },

    formattedValue() {
      if (!this.isNullValue) {
        const value = Nova.formatNumber(new String(this.value), this.format)

        return `${this.prefix}${value}`
      }

      return ''
    },

    formattedSuffix() {
      if (this.suffixInflection === false) {
        return this.suffix
      }

      return singularOrPlural(this.value, this.suffix)
    },
  },
}
</script>
