<template>
  <Sidebar :visible="sidebarTraces" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="false" class="!w-11/12" @show="show()">
    <template #header>
      <p class="h1">Traces</p>
    </template>
    <div class="pt-4 h-full flex items-center justify-start">
      <!-- Trace List -->
      <section class="w-80 h-full pr-4 border-r border-neutral-300">
        <p class="h2 px-2 mb-2">Trace List ({{ traceTotal }})</p>
        <p class="text-primary h2 px-2 mb-2">
          <span class="material-symbols-outlined !text-sm align-[-10%] mr-2">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">
            <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">#{{ trace.id }}</td>
                <td class="p-2 w-24">
                  <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 class="pl-4 h-full w-[calc(100%_-_320px)]">
        <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 w-full 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>
  </Sidebar>
</template>
<script>
import { storeToRefs } from 'pinia';
import LoadingStore from '@/stores/loading.js';
import AllMapDataStore from '@/stores/allMapData.js';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';

export default {
  props: ['sidebarTraces', 'cases'],
  setup() {
    const loadingStore = LoadingStore();
    const allMapDataStore = AllMapDataStore();
    const { isLoading } = storeToRefs(loadingStore);
    const { infinit404, infiniteStart, traceId, traces, traceTaskSeq, infiniteFirstCases } = storeToRefs(allMapDataStore);

    return {allMapDataStore, infinit404, infiniteStart, traceId, traces, traceTaskSeq, infiniteFirstCases, isLoading }
  },
  data() {
    return {
      processMap:{
        nodes:[],
        edges:[],
      },
      showTraceId: null,
      infinitMaxItems: false,
      infiniteData: [],
      infiniteFinish: true, // 無限滾動是否載入完成
    }
  },
  computed: {
    traceTotal: function() {
      return this.traces.length;
    },
    traceList: function() {
      let sum = this.traces.map(trace => trace.count).reduce((acc, cur) => acc + cur, 0);
      let result = this.traces.map(trace => {
        return {
          id: trace.id,
          value: this.progressWidth(Number(((trace.count / sum) * 100).toFixed(1))),
          count: trace.count.toLocaleString(),
          base_count: trace.count,
          ratio: this.getPercentLabel(trace.count / sum),
        };
      })
      return result;
    },
    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.cases)); // 深拷貝原始 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: {
    infinite404: function(newValue) {
      if(newValue === 404) this.infinitMaxItems = true;
    },
    traceId: {
      handler(newValue) {
        this.showTraceId = newValue;
      },
      immediate: true
    },
    showTraceId: function(newValue, oldValue) {
      let isScrollTop = document.querySelector('.infiniteTable');
      if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
    },
    infiniteFirstCases: function(newValue){
      if(this.infiniteFirstCases) this.infiniteData = JSON.parse(JSON.stringify(newValue));
    },
  },
  methods: {
    /**
     * Number to percentage
     * @param   {number} val
     * @returns {string}     轉換完成的百分比字串
     */
    getPercentLabel(val){
      if((val * 100).toFixed(1) >= 100) return `100%`;
      else return `${(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) {
      // 點同一筆 id 不要有動作
      if(id == this.showTraceId) return;
      // if(count >= 1000) this.isLoading = true; // 超過 1000 筆要 loading 畫面
      this.isLoading = true; // 都要 loading 畫面
      this.infinit404 = null;
      this.infinitMaxItems = false;
      this.showTraceId = id;
      this.infiniteStart = 0;
      this.$emit('switch-Trace-Id', {id: this.showTraceId, count: count}); // 傳遞到 Map index 再關掉 loading
    },
    /**
     * 將 trace element nodes 資料彙整
     */
    setNodesData(){
      // 避免每次渲染都重複累加
      this.processMap.nodes = [];
      // 將 api call 回來的資料帶進 node
      this.traceTaskSeq.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.traceTaskSeq.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);
    },
    /**
     * create map
     */
     async show() {
      this.isLoading = await true; // createCy 執行完關閉
      // 因 trace api 連動，所以關閉側邊欄時讓數值歸 traces 第一筆 id
      this.showTraceId = await this.traces[0]?.id;
      this.infiniteStart = await 0;
      this.setNodesData();
      this.setEdgesData();
      this.createCy();
      this.isLoading = false;
    },
    /**
     * 無限滾動: 監聽 scroll 有沒有滾到底部
     * @param {element} event
     */
    handleScroll(event) {
      if(this.infinitMaxItems || this.cases.length < 20 || this.infiniteFinish === false) return;

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

      if(overScrollHeight) this.fetchData();
    },
    /**
     * 無限滾動: 滾到底後，要載入數據
     */
    async fetchData() {
      try {
        this.isLoading = true;
        this.infiniteFinish = false;
        this.infiniteStart += 20;
        await this.allMapDataStore.getTraceDetail();
        this.infiniteData = await [...this.infiniteData, ...this.cases];
        this.infiniteFinish = await true;
        this.isLoading = await false;
      } catch(error) {
        console.error('Failed to load data:', error);
      }
    }
  },
}
</script>

<style scoped>
/* 進度條顏色 */
:deep(.p-progressbar .p-progressbar-value) {
  @apply bg-primary
}
/* 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>
