<template>
  <div id="heatmap" class="w-full">
    <div class="mx-auto" :style="{ height: innerHeight + 160 + 'px', width: innerWidth + 52 + 'px' }" style="background-color: rgba(13, 17, 23, 0)">
      <p class="mb-2 px-1 text-sm text-gray-200">{{ Object.values(daysListening).length }} listening sessions in the last year</p>
      <div class="border border-opacity-25 rounded py-2 w-full" style="background-color: #232323" :style="{ height: innerHeight + 80 + 'px' }">
        <div :style="{ width: innerWidth + 'px', height: innerHeight + 'px' }" class="ml-10 mt-5 absolute" @mouseover="mouseover" @mouseout="mouseout">
          <div v-for="dayLabel in dayLabels" :key="dayLabel.label" :style="dayLabel.style" class="absolute top-0 left-0 text-gray-300">{{ dayLabel.label }}</div>

          <div v-for="monthLabel in monthLabels" :key="monthLabel.id" :style="monthLabel.style" class="absolute top-0 left-0 text-gray-300">{{ monthLabel.label }}</div>

          <div v-for="(block, index) in data" :key="block.dateString" :style="block.style" :data-index="index" class="absolute top-0 left-0 h-2.5 w-2.5 rounded-sm" />

          <div class="flex py-2 px-4" :style="{ marginTop: innerHeight + 'px' }">
            <div class="flex-grow" />
            <p style="font-size: 10px; line-height: 10px" class="text-gray-400 px-1">Less</p>
            <div v-for="block in legendBlocks" :key="block.id" :style="block.style" class="h-2.5 w-2.5 rounded-sm" style="margin-left: 1.5px; margin-right: 1.5px" />
            <p style="font-size: 10px; line-height: 10px" class="text-gray-400 px-1">More</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    daysListening: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      contentWidth: 0,
      maxInnerWidth: 0,
      innerHeight: 13 * 7,
      blockWidth: 13,
      data: [],
      monthLabels: [],
      tooltipEl: null,
      tooltipTextEl: null,
      tooltipArrowEl: null,
      showingTooltipIndex: -1,
      outlineColors: ['rgba(27, 31, 35, 0.06)', 'rgba(255,255,255,0.03)'],
      bgColors: ['rgb(45,45,45)', 'rgb(14, 68, 41)', 'rgb(0, 109, 50)', 'rgb(38, 166, 65)', 'rgb(57, 211, 83)']
      // GH Colors
      // outlineColors: ['rgba(27, 31, 35, 0.06)', 'rgba(255,255,255,0.05)'],
      // bgColors: ['rgb(22, 27, 34)', 'rgb(14, 68, 41)', 'rgb(0, 109, 50)', 'rgb(38, 166, 65)', 'rgb(57, 211, 83)']
    }
  },
  computed: {
    weeksToShow() {
      return Math.min(52, Math.floor(this.maxInnerWidth / this.blockWidth) - 1)
    },
    innerWidth() {
      return (this.weeksToShow + 1) * 13
    },
    daysToShow() {
      return this.weeksToShow * 7 + this.dayOfWeekToday
    },
    dayOfWeekToday() {
      return new Date().getDay()
    },
    firstWeekStart() {
      return this.$addDaysToToday(-this.daysToShow)
    },
    dayLabels() {
      return [
        {
          label: 'Mon',
          style: {
            transform: `translate(${-25}px, ${13}px)`,
            lineHeight: '10px',
            fontSize: '10px'
          }
        },
        {
          label: 'Wed',
          style: {
            transform: `translate(${-25}px, ${13 * 3}px)`,
            lineHeight: '10px',
            fontSize: '10px'
          }
        },
        {
          label: 'Fri',
          style: {
            transform: `translate(${-25}px, ${13 * 5}px)`,
            lineHeight: '10px',
            fontSize: '10px'
          }
        }
      ]
    },
    legendBlocks() {
      return [
        {
          id: 'legend-0',
          style: `background-color:${this.bgColors[0]};outline:1px solid ${this.outlineColors[0]};outline-offset:-1px;`
        },
        {
          id: 'legend-1',
          style: `background-color:${this.bgColors[1]};outline:1px solid ${this.outlineColors[1]};outline-offset:-1px;`
        },
        {
          id: 'legend-2',
          style: `background-color:${this.bgColors[2]};outline:1px solid ${this.outlineColors[1]};outline-offset:-1px;`
        },
        {
          id: 'legend-3',
          style: `background-color:${this.bgColors[3]};outline:1px solid ${this.outlineColors[1]};outline-offset:-1px;`
        },
        {
          id: 'legend-4',
          style: `background-color:${this.bgColors[4]};outline:1px solid ${this.outlineColors[1]};outline-offset:-1px;`
        }
      ]
    }
  },
  methods: {
    destroyTooltip() {
      if (this.tooltipEl) this.tooltipEl.remove()
      this.tooltipEl = null
      this.showingTooltipIndex = -1
    },
    createTooltip() {
      const tooltip = document.createElement('div')
      tooltip.className = 'absolute top-0 left-0 rounded bg-gray-500 text-white p-2 text-white max-w-xs pointer-events-none'
      tooltip.style.display = 'none'
      tooltip.id = 'heatmap-tooltip'

      const tooltipText = document.createElement('p')
      tooltipText.innerText = 'Tooltip'
      tooltipText.style.fontSize = '10px'
      tooltipText.style.lineHeight = '10px'
      tooltip.appendChild(tooltipText)

      const tooltipArrow = document.createElement('div')
      tooltipArrow.className = 'text-gray-500 arrow-down-small absolute -bottom-1 left-0 right-0 mx-auto'
      tooltip.appendChild(tooltipArrow)

      this.tooltipEl = tooltip
      this.tooltipTextEl = tooltipText
      this.tooltipArrowEl = tooltipArrow

      document.body.appendChild(this.tooltipEl)
    },
    showTooltip(index, block, rect) {
      if (this.tooltipEl && this.showingTooltipIndex === index) return
      if (!this.tooltipEl) {
        this.createTooltip()
      }

      this.showingTooltipIndex = index
      this.tooltipEl.style.display = 'block'
      this.tooltipTextEl.innerHTML = block.value ? `<strong>${this.$elapsedPretty(block.value, true)} listening</strong> on ${block.datePretty}` : `No listening sessions on ${block.datePretty}`

      const calculateRect = this.tooltipEl.getBoundingClientRect()

      const w = calculateRect.width / 2
      var left = rect.x - w
      var offsetX = 0
      if (left < 0) {
        offsetX = Math.abs(left)
        left = 0
      } else if (rect.x + w > window.innerWidth - 10) {
        offsetX = window.innerWidth - 10 - (rect.x + w)
        left += offsetX
      }

      this.tooltipEl.style.transform = `translate(${left}px, ${rect.y - 32}px)`
      this.tooltipArrowEl.style.transform = `translate(${5 - offsetX}px, 0px)`
    },
    hideTooltip() {
      if (this.showingTooltipIndex >= 0 && this.tooltipEl) {
        this.tooltipEl.style.display = 'none'
        this.showingTooltipIndex = -1
      }
    },
    mouseover(e) {
      if (isNaN(e.target.dataset.index)) {
        this.hideTooltip()
        return
      }
      var block = this.data[e.target.dataset.index]
      var rect = e.target.getBoundingClientRect()
      this.showTooltip(e.target.dataset.index, block, rect)
    },
    mouseout(e) {
      this.hideTooltip()
    },
    buildData() {
      this.data = []

      var maxValue = 0
      var minValue = 0
      Object.values(this.daysListening).forEach((val) => {
        if (val > maxValue) maxValue = val
        if (!minValue || val < minValue) minValue = val
      })
      const range = maxValue - minValue + 0.01

      for (let i = 0; i < this.daysToShow + 1; i++) {
        const col = Math.floor(i / 7)
        const row = i % 7

        const date = i === 0 ? this.firstWeekStart : this.$addDaysToDate(this.firstWeekStart, i)
        const dateString = this.$formatJsDate(date, 'yyyy-MM-dd')
        const datePretty = this.$formatJsDate(date, 'MMM d, yyyy')
        const monthString = this.$formatJsDate(date, 'MMM')
        const value = this.daysListening[dateString] || 0
        const x = col * 13
        const y = row * 13

        var bgColor = this.bgColors[0]
        var outlineColor = this.outlineColors[0]
        if (value) {
          outlineColor = this.outlineColors[1]
          var percentOfAvg = (value - minValue) / range
          var bgIndex = Math.floor(percentOfAvg * 4) + 1
          bgColor = this.bgColors[bgIndex] || 'red'
        }

        this.data.push({
          date,
          dateString,
          datePretty,
          monthString,
          dayOfMonth: Number(dateString.split('-').pop()),
          yearString: dateString.split('-').shift(),
          value,
          col,
          row,
          style: `transform:translate(${x}px,${y}px);background-color:${bgColor};outline:1px solid ${outlineColor};outline-offset:-1px;`
        })
      }
      console.log('Data', this.data)

      this.monthLabels = []
      var lastMonth = null
      for (let i = 0; i < this.data.length; i++) {
        if (this.data[i].monthString !== lastMonth) {
          const weekOfMonth = Math.floor(this.data[i].dayOfMonth / 7)
          if (weekOfMonth <= 2) {
            this.monthLabels.push({
              id: this.data[i].dateString + '-ml',
              label: this.data[i].monthString,
              style: {
                transform: `translate(${this.data[i].col * 13}px, -15px)`,
                lineHeight: '10px',
                fontSize: '10px'
              }
            })
            lastMonth = this.data[i].monthString
          }
        }
      }
    },
    init() {
      const heatmapEl = document.getElementById('heatmap')
      this.contentWidth = heatmapEl.clientWidth
      this.maxInnerWidth = this.contentWidth - 52
      this.buildData()
    }
  },
  updated() {},
  mounted() {
    this.init()
  },
  beforeDestroy() {}
}
</script>