<template>
<div class="flex justify-between items-start bg-neutral-10 border border-neutral-300 rounded-xl px-4 w-full h-full space-x-4 overflow-y-auto overflow-x-auto scrollbar">
    <!-- Range Selection -->
    <section class="py-2 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 a percentage range.</p>
      </div>
      <Chart type="bar" :data="chartData" :options="chartOptions" class="h-2/5" />
      <div class="px-2">
        <p class="py-4">Select percentage of case <span class=" float-right">{{ caseTotalPercent }}%</span></p>
        <Slider v-model="selectArea" :step="1" :min="0" :max="traceTotal" range class="mx-2" />
      </div>
    </section>
    <!-- Trace List -->
    <section class="h-full min-w-[48%] py-2 space-y-2">
      <p class="h2">Trace List ({{ traceTotal }})</p>
      <p class="text-primary h2 flex items-center justify-start">
        <span class="material-symbols-outlined mr-2 text-base">info</span>Click trace number to see more.
      </p>
      <div class="overflow-y-scroll overflow-x-hidden scrollbar mx-[-8px] max-h-[calc(100%_-_96px)]" >
        <table class="border-separate border-spacing-x-2 text-sm w-full">
          <thead class="sticky top-0 z-10 bg-neutral-10">
            <tr>
              <th class="h2 px-2 border-b border-neutral-500">Trace</th>
              <th class="h2 px-2 border-b border-neutral-500 text-start" colspan="3">Occurrences</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(trace, key) in traceList" :key="key" class=" cursor-pointer hover:text-primary" @click="switchCaseData(trace.id, trace.base_count)">
              <td class="p-2 text-center">#{{ trace.id }}</td>
              <td class="p-2 min-w-[96px]">
                <div class="h-4 w-full bg-neutral-300 rounded-sm overflow-hidden">
                  <div class="h-full bg-primary" :style="trace.value"></div>
                </div>
              </td>
              <td class="py-2 text-right">{{ trace.count }}</td>
              <td class="p-2 text-right">{{ trace.ratio }}%</td>
            </tr>
          </tbody>
        </table>
      </div>
    </section>
    <!-- Trace item Table -->
    <section v-show="showTraceId" class="pl-4 h-full min-w-full py-2 space-y-2">
      <p class="h2 mb-2">Trace #{{ showTraceId }}</p>
      <div class="h-36 w-full px-2 mb-2 border border-neutral-300 rounded">
        <div class="h-full w-full">
          <div id="cyTrace" ref="cyTrace" class="h-full min-w-full relative"></div>
        </div>
      </div>
      <div class="overflow-y-auto overflow-x-auto scrollbar h-[calc(100%_-_200px)] infiniteTable" @scroll="handleScroll">
        <DataTable :value="caseData" showGridlines tableClass="text-sm" breakpoint="0">
          <div v-for="(col, index) in columnData" :key="index">
            <Column :field="col.field" :header="col.header">
              <template #body="{ data }">
                <div :class="data[col.field]?.length > 18 ? 'whitespace-normal' : 'whitespace-nowrap'">
                    {{ data[col.field] }}
                </div>
              </template>
            </Column>
          </div>
        </DataTable>
      </div>
    </section>
</div>
</template>

<script>
import { storeToRefs } from 'pinia';
import AllMapDataStore from '@/stores/allMapData.js';
import LoadingStore from '@/stores/loading.js';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';

export default {
  expose: ['selectArea', 'showTraceId', 'traceTotal'],
  setup() {
    const allMapDataStore = AllMapDataStore();
    const loadingStore = LoadingStore();
    const { infinit404, baseInfiniteStart, baseTraces, baseTraceTaskSeq, baseCases } = storeToRefs(allMapDataStore);
    const { isLoading } = storeToRefs(loadingStore);

    return {allMapDataStore, infinit404, baseInfiniteStart, baseTraces, baseTraceTaskSeq, baseCases, isLoading}
  },
  data() {
    return {
      processMap:{
        nodes:[],
        edges:[],
      },
      showTraceId: null,
      infinitMaxItems: false,
      infiniteData: [],
      chartOptions: null,
      selectArea: [0, 1]
    }
  },
  computed: {
    traceTotal: function() {
      return this.baseTraces.length;
    },
    traceCountTotal: function() {
      return this.baseTraces.map(trace => trace.count).reduce((acc, cur) => acc + cur, 0);
    },
    traceList: function() {
      return this.baseTraces.map(trace => {
        return {
          id: trace.id,
          value: this.progressWidth(Number(((trace.count / this.traceCountTotal) * 100).toFixed(1))),
          count: trace.count.toLocaleString(),
          base_count: trace.count,
          ratio: this.getPercentLabel(trace.count / this.traceCountTotal),
        };
      }).slice(this.selectArea[0], this.selectArea[1]);
    },
    caseTotalPercent: function() {
      let ratioSum = this.traceList.map(trace => trace.base_count).reduce((acc, cur) => acc + cur, 0) / this.traceCountTotal;
      return this.getPercentLabel(ratioSum)
    },
    chartData: function() {
      const start = this.selectArea[0];
      const end = this.selectArea[1] - 1;
      const labels = this.baseTraces.map(trace => `#${trace.id}`);
      const data = this.baseTraces.map(trace => this.getPercentLabel(trace.count / this.traceCountTotal));
      const selectAreaData = this.baseTraces.map((trace, index) => index >= start && index <= end ? 'rgba(0,153,255)' : 'rgba(203, 213, 225)');

      return { // 要呈現的資料
        labels,
        datasets: [
          {
            label: 'Trace', // 資料的標題標籤
            data,
            backgroundColor: selectAreaData,
            categoryPercentage: 1.0,
            barPercentage: 1.0
          },
        ]
      };
    },
    caseData: function() {
      const data = JSON.parse(JSON.stringify(this.infiniteData)); // 深拷貝原始 cases 的內容
      data.forEach(item => {
        item.attributes.forEach((attribute, index) => {
          item[`att_${index}`] = attribute.value; // 建立新的 key-value pair
        });
        delete item.attributes; // 刪除原本的 attributes 屬性
      })
      return data;
    },
    columnData: function() {
      const data = JSON.parse(JSON.stringify(this.baseCases)); // 深拷貝原始 cases 的內容
      let result = [
          { field: 'id', header: 'Case Id' },
          { field: 'started_at', header: 'Start time' },
          { field: 'completed_at', header: 'End time' },
        ];
      if(data.length !== 0){
        result = [
          { field: 'id', header: 'Case Id' },
          { field: 'started_at', header: 'Start time' },
          { field: 'completed_at', header: 'End time' },
          ...data[0]?.attributes.map((att, index) => ({ field: `att_${index}`, header: att.key })),
        ];
      }
      return result
    },
  },
  watch: {
    selectArea: function(newValue) {
      let roundValue = Math.round(newValue[1].toFixed());
      if(newValue[1] !== roundValue) this.selectArea[1] = roundValue;
    },
    infinite404: function(newValue) {
      if(newValue === 404) this.infinitMaxItems = true;
    },
    showTraceId: function(newValue, oldValue) {
      let isScrollTop = document.querySelector('.infiniteTable');
      if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
    },
  },
  methods: {
    /**
     * Set bar chart Options
     */
    barOptions(){
      return {
        maintainAspectRatio: false,
        aspectRatio: 0.8,
        layout: {
          padding: {
            top: 16,
            left: 8,
            right: 8,
          }
        },
        plugins: {
          legend: { // 圖例
            display: false,
          },
          tooltip: {
            callbacks: {
              label: (tooltipItems) =>{
                return `${tooltipItems.dataset.label}: ${tooltipItems.parsed.y}%`
              }
            }
          }
        },
        animations: false,
        scales: {
          x: {
            display:false
          },
          y: {
            ticks: { // 設定間隔數值
              display: false, // 隱藏數值，只顯示格線
              min: 0,
              max: this.traceList[0]?.ratio,
              stepSize: (this.traceList[0]?.ratio)/4,
            },
            grid: {
              color: 'rgba(100,116,139)',
              z: 1,
            },
            border: {
              display: false, // 隱藏左側多出來的線
            }
          }
        }
      };
    },
    /**
     * Number to percentage
     * @param   {number} val
     * @returns {string}     轉換完成的百分比字串
     */
     getPercentLabel(val){
      if((val * 100).toFixed(1) >= 100) return 100;
      else return parseFloat((val * 100).toFixed(1));
    },
    /**
     * set progress bar width
     * @param   {number} value
     * @returns {string}      樣式的寬度設定
     */
     progressWidth(value){
      return `width:${value}%;`
    },
    /**
     * switch case data
     * @param {number} id
     */
     async switchCaseData(id, count) {
      if(count >= 1000) this.isLoading = true;
      this.infinit404 = null;
      this.infinitMaxItems = false;
      this.showTraceId = id;
      this.baseInfiniteStart = 0;
      this.allMapDataStore.baseTraceId = id;
      this.infiniteData = await this.allMapDataStore.getBaseTraceDetail();
      this.createCy();
      this.isLoading = false;
    },
    /**
     * 將 trace element nodes 資料彙整
     */
     setNodesData(){
      // 避免每次渲染都重複累加
      this.processMap.nodes = [];
      // 將 api call 回來的資料帶進 node
      this.baseTraceTaskSeq.forEach((node, index) => {
        this.processMap.nodes.push({
          data: {
            id: index,
            label: node,
            backgroundColor: '#CCE5FF',
            bordercolor: '#003366',
            shape: 'round-rectangle',
            height: 80,
            width: 100
          }
        });
      })
    },
    /**
     * 將 trace edge line 資料彙整
     */
    setEdgesData(){
      this.processMap.edges = [];
      this.baseTraceTaskSeq.forEach((edge, index) => {
        this.processMap.edges.push({
          data: {
            source: `${index}`,
            target: `${index + 1}`,
            lineWidth: 1,
            style: 'solid'
          }
        });
      });
      // 關係線數量筆節點少一個
      this.processMap.edges.pop();
    },
    /**
     * create trace cytoscape's map
     */
     createCy(){
      let graphId = this.$refs.cyTrace;

      this.setNodesData();
      this.setEdgesData();
      cytoscapeMapTrace(this.processMap.nodes, this.processMap.edges, graphId);
    },
    /**
     * 無限滾動: 監聽 scroll 有沒有滾到底部
     * @param {element} event
     */
     handleScroll(event) {
      if(this.infinitMaxItems || this.baseCases.length < 20) return;

      const container = event.target;
      const overScrollHeight = container.scrollTop + container.clientHeight >= container.scrollHeight;

      if(overScrollHeight) this.fetchData();
    },
    /**
     * 無限滾動: 滾到底後，要載入數據
     */
    async fetchData() {
      try {
        this.baseInfiniteStart += 20;
        await this.allMapDataStore.getBaseTraceDetail();
        this.infiniteData = [...this.infiniteData, ...this.baseCases];
      } catch(error) {
        console.error('Failed to load data:', error);
      }
    }
  },
  mounted() {
    this.isLoading = true; // createCy 執行完關閉
    this.setNodesData();
    this.setEdgesData();
    this.createCy();
    this.chartOptions = this.barOptions();
    this.selectArea = [0, this.traceTotal]
    this.isLoading = false;
  },
}
</script>

<style scoped>
/* Table set */
:deep(.p-datatable-thead) {
  @apply sticky top-0 left-0 z-10 bg-neutral-10
}
:deep(.p-datatable .p-datatable-thead > tr > th) {
  @apply !border-y-0 border-neutral-500 bg-neutral-100 after:absolute after:left-0 after:w-full after:h-full after:block after:top-0 after:border-b after:border-t after:border-neutral-500
}
:deep(.p-datatable .p-datatable-tbody > tr > td) {
  @apply border-neutral-500 !border-t-0
}
:deep(.p-datatable .p-datatable-thead > tr > th) {
  white-space: nowrap;
}
:deep(.p-datatable.p-datatable-gridlines .p-datatable-tbody > tr > td) {
  min-width: 72px;
  max-width: 184px;
  overflow-wrap: break-word;
  word-wrap: break-word;
}
</style>
