<template>
<Dialog :visible="listModal" @update:visible="$emit('closeModal', $event)"  modal :style="{ width: '90vw', height: '90vh' }" :contentClass="contentClass">
  <template #header>
    <div class=" py-5">
      <p class="text-base font-bold">Non-conformance Issue</p>
    </div>
  </template>
  <div class="h-full flex items-start justify-start p-4">
    <!-- Trace List -->
    <section class="w-80 h-full pr-4">
      <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-100">
            <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)">
              <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="progressWidth(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="px-4 py-2 h-full w-[calc(100%_-_320px)] bg-neutral-10 rounded-xl">
      <p class="h2 mb-2 px-4">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="cfmTrace" ref="cfmTrace" 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>
</Dialog>
</template>
<script>
import { storeToRefs } from 'pinia';
import ConformanceStore from '@/stores/conformance.js';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';

export default {
  props: ['listModal', 'listNo', 'traceId', 'firstCases', 'listTraces', 'taskSeq', 'cases', 'category'],
  setup() {
    const conformanceStore = ConformanceStore();
    const { infinite404 } = storeToRefs(conformanceStore);

    return { infinite404, conformanceStore }
  },
  data() {
    return {
      contentClass: '!bg-neutral-100 border-t border-neutral-300 h-full',
      showTraceId: null,
      infiniteData: null,
      maxItems: false,
      infiniteFinish: true, // 無限滾動是否載入完成
      startNum: 0,
      processMap:{
        nodes:[],
        edges:[],
      },
    }
  },
  computed: {
    traceTotal: function() {
      return this.traceList.length;
    },
    traceList: function() {
      let sum = this.listTraces.map(trace => trace.count).reduce((acc, cur) => acc + cur, 0);

      return this.listTraces.map(trace => {
        return {
          id: trace.id,
          value: Number((this.getPercentLabel(trace.count / sum))),
          count: trace.count.toLocaleString('en-US'),
          count_base: trace.count,
          ratio: this.getPercentLabel(trace.count / sum),
        };
      }).sort((x, y) => x.id - y.id);
    },
    caseData: function() {
      if(this.infiniteData !== null){
        const data = JSON.parse(JSON.stringify(this.infiniteData)); // 深拷貝原始 cases 的內容
        data.forEach(item => {
          item.facets.forEach((facet, index) => {
            item[`fac_${index}`] = facet.value; // 建立新的 key-value pair
          });
          delete item.facets; // 刪除原本的 facets 屬性

          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 的內容
      const facetName = facName => facName.trim().replace(/^(.)(.*)$/, (match, firstChar, restOfString) => firstChar.toUpperCase() + restOfString.toLowerCase());

      const result = [
        { field: 'id', header: 'Case Id' },
        { field: 'started_at', header: 'Start time' },
        { field: 'completed_at', header: 'End time' },
        ...data[0].facets.map((fac, index) => ({ field: `fac_${index}`, header: facetName(fac.name) })),
        ...data[0].attributes.map((att, index) => ({ field: `att_${index}`, header: att.key })),
      ];
      return result
    },
  },
  watch: {
    listModal: function(newValue) { // 第一次打開 Modal 要繪圖
      if(newValue) this.createCy();
    },
    taskSeq: function(newValue){
      if (newValue != null) this.createCy();
    },
    traceId: function(newValue) {
      // 當 traceId 屬性變化時更新 showTraceId
      this.showTraceId = newValue;
    },
    showTraceId: function(newValue, oldValue) {
      let isScrollTop = document.querySelector('.infiniteTable');
      if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
    },
    firstCases: function(newValue, oldValue){
      this.infiniteData = newValue;
    },
    infinite404: function(newValue, oldValue){
      if (newValue === 404) this.maxItems = true;
    },
  },
  methods: {
    /**
     * 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) {
      if(id == this.showTraceId) return;
      this.infinite404 = null;
      this.maxItems = false;
      this.startNum = 0;

      let result;
      if(this.category === 'issue') result = await this.conformanceStore.getConformanceTraceDetail(this.listNo, id, 0);
      else if(this.category === 'loop') result = await this.conformanceStore.getConformanceLoopsTraceDetail(this.listNo, id, 0);
      this.infiniteData = await result;
      this.showTraceId = id; // 放 getDetail 為了 case table 載入完再切換 showTraceId
    },
    /**
     * 將 trace element nodes 資料彙整
     */
     setNodesData(){
      // 避免每次渲染都重複累加
      this.processMap.nodes = [];
      // 將 api call 回來的資料帶進 node
      if(this.taskSeq != null) {
        this.taskSeq.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 = [];
      if(this.taskSeq != null) {
        this.taskSeq.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(){
      this.$nextTick(() => {
        let graphId = this.$refs.cfmTrace;

        this.setNodesData();
        this.setEdgesData();
        if(graphId != null) cytoscapeMapTrace(this.processMap.nodes, this.processMap.edges, graphId);
      });
    },
    /**
     * 無限滾動: 載入數據
     */
    async fetchData() {
      try {
        this.infiniteFinish = false;
        this.startNum += 20
        const result = await this.conformanceStore.getConformanceTraceDetail(this.listNo, this.showTraceId, this.startNum);
        this.infiniteData = await [...this.infiniteData, ...result];
        this.infiniteFinish = await true;
      } catch(error) {
        console.error('Failed to load data:', error);
      }
    },
    /**
     * 無限滾動: 監聽 scroll 有沒有滾到底部
     * @param {element} event
     */
    handleScroll(event) {
      if(this.maxItems || this.infiniteData.length < 20 || this.infiniteFinish === false) return;

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

      if (overScrollHeight) this.fetchData();
    },
  },
}
</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 text-center
}
/* 標題置中 */
:deep(.p-column-header-content) {
  @apply justify-center
}
: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>
