<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"
        :value="selectedRangeKey"
        @update:modelValue="$emit('selected', $event)"
        :options="ranges"
        size="xxs"
        class="ml-auto w-[6rem] shrink-0"
        :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 { singularOrPlural } from '@/util'

import { LineChart, Interpolation } from 'chartist'
import 'chartist/dist/index.css'
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 LineChart(
      this.$refs.chart,
      { series: this.chartData },
      {
        lineSmooth: 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)
    },

    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>
