<template>
  <div class="bg-neutral-10 border border-neutral-300 rounded-xl px-4 w-full h-full">
    <section class="pt-2 pb-20 space-y-2 text-sm min-w-[48%] h-full">
      <p class="h2">Range Selection</p>
      <div class="text-primary h2 flex items-center justify-start">
        <span class="material-symbols-outlined mr-2 !text-base">info</span>
        <p>Select or fill in a time range.</p>
      </div>
      <div class="chartContainer h-3/5 relative">
        <canvas id="chartCanvasId"></canvas>
        <div id="chart-mask-left" class="absolute bg-neutral-10/50"></div>
        <div id="chart-mask-right" class="absolute bg-neutral-10/50"></div>
      </div>
      <div class="px-2 py-3">
        <Slider v-model="selectArea" :step="1" :min="0" :max="selectRange" range class="mx-2" @change="changeSelectArea($event)"/>
      </div>
      <!-- Calendar group -->
      <div class="flex justify-center items-center space-x-2 w-full">
        <div>
          <span class="block mb-2">Start time</span>
          <Calendar v-model="startTime" dateFormat="yy/mm/dd" :panelProps="panelProps" :minDate="startMinDate" :maxDate="startMaxDate" showTime showIcon hourFormat="24" @date-select="sliderTimeRange($event, 'start')" id="startCalendar"/>
        </div>
        <span class="block mt-4">~</span>
        <div>
          <span class="block mb-2">End time</span>
          <Calendar v-model="endTime" dateFormat="yy/mm/dd" :panelProps="panelProps" :minDate="endMinDate" :maxDate="endMaxDate" showTime showIcon hourFormat="24" @date-select="sliderTimeRange($event, 'end')" id="endCalendar"/>
        </div>
      </div>
      <!-- End calendar group -->
    </section>
  </div>
</template>
<script>
import { storeToRefs } from 'pinia';
import AllMapDataStore from '@/stores/allMapData.js';
import { Chart, registerables } from 'chart.js';
import 'chartjs-adapter-date-fns';
import getMoment from 'moment';

export default{
  props:['selectValue'],
  setup() {
    const allMapDataStore = AllMapDataStore();
    const { filterTimeframe, selectTimeFrame } = storeToRefs(allMapDataStore);

    return {allMapDataStore, filterTimeframe, selectTimeFrame }
  },
  data() {
    return {
      selectRange: 1000, // 更改 select 的切分數
      selectArea: null,
      chart: null,
      canvasId: null,
      startTime: null,
      endTime: null,
      startMinDate: null,
      startMaxDate: null,
      endMinDate: null,
      endMaxDate: null,
      panelProps: {
        onClick: (event) => {
          event.stopPropagation();
        },
      },
    }
  },
  computed: {
    // user select time start and end
    timeFrameStartEnd: function() {
      let start = getMoment(this.startTime).format('YYYY-MM-DDTHH:mm:00');
      let end = getMoment(this.endTime).format('YYYY-MM-DDTHH:mm:00');
      this.selectTimeFrame = [start, end]; // 傳給後端的資料

      return [start, end];
    },
    // 找出 slidrData，時間格式:毫秒時間戳
    sliderData: function() {
      let xAxisMin = new Date(this.filterTimeframe.x_axis.min).getTime();
      let xAxisMax = new Date(this.filterTimeframe.x_axis.max).getTime();
      let range = xAxisMax - xAxisMin;
      let step = range / this.selectRange;
      let sliderData = []

      for (let i = 0; i <= this.selectRange; i++) {
        sliderData.push(xAxisMin + (step * i));
      }

      return sliderData;
    },
    // 加入最大、最小值
    timeFrameData: function(){
      let data = this.filterTimeframe.data.map(i=>({x:i.x,y:i.y}))
      // y 軸斜率計算請參考 ./public/timeFrameSlope 的圖
      // x 值為 0 ~ 11,
      // 將三的座標(ax, ay), (bx, by), (cx, cy)命名為 (a, b), (c, d), (e, f)
      // 最小值: (f - b)(c - a) = (e - a)(d - b)，求 b = (ed - ad - fa - fc) / (e - c - a)
      // 最大值: (f - b)(e - c) = (f - d)(e - a)，求 f = (be - bc -de + da) / (a - c)

      // y 軸最小值
      let a = 0;
      let b;
      let c = 1;
      let d = this.filterTimeframe.data[0].y;
      let e = 2;
      let f = this.filterTimeframe.data[1].y;
      b = (e*d - a*d - f*a - f*c) / (e - c - a)
      b < 0 ? b = 0 : b;
      // y 軸最大值
      let ma = 9;
      let mb = this.filterTimeframe.data[8].y;
      let mc = 10;
      let md = this.filterTimeframe.data[9].y;
      let me = 11;
      let mf;
      mf = (mb*me - mb*mc -md*me + md*ma) / (ma - mc);
      mf < 0 ? mf = 0 : mf;

      // 添加最小值
      data.unshift({
        x: this.filterTimeframe.x_axis.min_base,
        y: b,
      })
      // 添加最大值
      data.push({
        x: this.filterTimeframe.x_axis.max_base,
        y: mf,
      })

      return data;
    },
    labelsData: function() {
      let min = new Date(this.filterTimeframe.x_axis.min_base).getTime();
      let max = new Date(this.filterTimeframe.x_axis.max_base).getTime();
      let numPoints = 11;
      let step = (max - min) / (numPoints - 1);
      let data = [];
      for(let i = 0; i< numPoints; i++) {
        const x = min + i * step;
        data.push(x);
      }
      return data;
    },
  },
  watch:{
    selectTimeFrame(newValue, oldValue) {
      if(newValue.length === 0) {
        this.startTime = new Date(this.filterTimeframe.x_axis.min);
        this.endTime = new Date(this.filterTimeframe.x_axis.max);
        this.selectArea = [0, this.selectRange];
        this.resizeMask(this.chart);
      }
    },
  },
  methods: {
    resizeMask(chart) {
      let from = (this.selectArea[0] * 0.01) / (this.selectRange * 0.01);
      let to = (this.selectArea[1] * 0.01) / (this.selectRange * 0.01);
      if(this.selectValue[0] === 'Timeframes') {
        this.resizeLeftMask(chart, from);
        this.resizeRightMask(chart, to);
      }
    },
    resizeLeftMask(chart, from) {
      const canvas = document.getElementById("chartCanvasId");
      const mask = document.getElementById("chart-mask-left");
      mask.style.left = `${canvas.offsetLeft + chart.chartArea.left}px`;
      mask.style.width = `${chart.chartArea.width * from}px`;
      mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`;
      mask.style.height = `${chart.chartArea.height}px`;
    },
    resizeRightMask(chart, to) {
      const canvas = document.getElementById("chartCanvasId");
      const mask = document.getElementById("chart-mask-right");
      mask.style.left = `${canvas.offsetLeft + chart.chartArea.left + chart.chartArea.width * to}px`;
      mask.style.width = `${chart.chartArea.width * (1 - to)}px`;
      mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`;
      mask.style.height = `${chart.chartArea.height}px`;
    },
    createChart() {
      const max = this.filterTimeframe.y_axis.max * 1.1;
      const minX = this.timeFrameData[0]?.x;
      const maxX = this.timeFrameData[this.timeFrameData.length - 1]?.x;

      const data = {
        labels:this.labelsData,
        datasets: [
          {
            label: 'Case',
            data: this.timeFrameData,
            fill: 'start',
            showLine: false,
            tension: 0.4,
            backgroundColor: 'rgba(0,153,255)',
            pointRadius: 0,
            x: 'x',
            y: 'y',
          }
        ]
      };
      const options = {
        responsive: true,
        maintainAspectRatio: false,
        layout: {
          padding: {
            top: 16,
            left: 8,
            right: 8,
          }
        },
        plugins: {
          legend: false, // 圖例
          filler: {
            propagate: false
          },
          title: false
        },
        // animations: false, // 取消動畫
        animation: {
          onComplete: e => {
            this.resizeMask(e.chart);
          }
        },
        interaction: {
          intersect: true,
        },
        scales: {
          x: {
            type: 'time',
            min: minX,
            max: maxX,
            ticks: {
              autoSkip: true,
              maxRotation: 0, // 不旋轉 lable 0~50
              color: '#334155',
              display: true,
              source: 'labels',
            },
            grid: {
              display: false, // 隱藏 x 軸網格
            },
            time: {
              minUnit: 'day', // 顯示最小單位
              // displayFormats: {
              //   minute: 'HH:mm MMM d',
              //   hour: 'HH:mm MMM d',
              // }
            }
          },
          y: {
            beginAtZero: true, // scale 包含 0
            max: max,
            ticks: { // 設定間隔數值
              display: false, // 隱藏數值，只顯示格線
              stepSize: max / 4,
            },
            grid: {
              color: 'rgba(100,116,139)',
              z: 1,
            },
            border: {
              display: false, // 隱藏左側多出來的線
            }
          },
        },
      };
      const config =  {
        type: 'line',
        data: data,
        options: options,
      };
      this.canvasId = document.getElementById("chartCanvasId");
      this.chart = new Chart(this.canvasId, config);
    },
    /**
     * 滑塊改變的時候
     * @param {array} e [1, 100]
     */
    changeSelectArea(e) {
      // 日曆改變時，滑塊跟著改變
      let sliderData = this.sliderData;
      let start = sliderData[e[0].toFixed()];
      let end = sliderData[e[1].toFixed()]; // 取得 index，須為整數。

      this.startTime = new Date(start);
      this.endTime = new Date(end);
      // 重新設定 start end 日曆選取範圍
      this.endMinDate = new Date(start);
      this.startMaxDate = new Date(end);
      // 重新算圖
      this.resizeMask(this.chart);
      // 執行 timeFrameStartEnd 才會改變數據
      this.timeFrameStartEnd;
    },
    /**
     * 選取開始或結束時間時，要改變滑塊跟圖表
     * @param {object} e Tue Jan 25 2022 00:00:00 GMT+0800 (台北標準時間)
     * @param {string} direction start or end
     */
    sliderTimeRange(e, direction) {
      // 找到最鄰近的 index，時間格式: 毫秒時間戳
      let sliderData = this.sliderData;
      const targetTime = [new Date(this.timeFrameStartEnd[0]).getTime(), new Date(this.timeFrameStartEnd[1]).getTime()];
      const closestIndexes = targetTime.map(target => {
        let closestIndex = 0;
        closestIndex = ((target - sliderData[0])/(sliderData[sliderData.length-1]-sliderData[0])) * sliderData.length;
        let result = Math.round(Math.abs(closestIndex));
        result = result > this.selectRange ? this.selectRange : result;
        return result
      });

      // 改變滑塊
      this.selectArea = closestIndexes;
      // 重新設定 start end 日曆選取範圍
      if(direction === 'start') this.endMinDate = e;
      else if(direction === 'end') this.startMaxDate = e;
      // 重新算圖
      if(!isNaN(closestIndexes[0]) && !isNaN(closestIndexes[1])) this.resizeMask(this.chart);
      else return;
    },
  },
  mounted() {
    // Chart.js
    Chart.register(...registerables);
    this.createChart();
    // Slider
    this.selectArea = [0, this.selectRange];
    // Calendar
    this.startMinDate = new Date(this.filterTimeframe.x_axis.min);
    this.startMaxDate = new Date(this.filterTimeframe.x_axis.max);
    this.endMinDate = new Date(this.filterTimeframe.x_axis.min);
    this.endMaxDate = new Date(this.filterTimeframe.x_axis.max);
    // 讓日曆的範圍等於時間軸的範圍
    this.startTime = this.startMinDate;
    this.endTime = this.startMaxDate;
    this.timeFrameStartEnd;
  },
}
</script>
