<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">
          <caption class="hidden">Trace List</caption>
          <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 setup>
// The Lucia project.
// Copyright 2023-2026 DSP, inc.  All rights reserved.
// Authors:
//   chiayin.kuo@dsp.im (chiayin), 2023/1/31
//   cindy.chang@dsp.im (Cindy Chang), 2024/5/30
//   imacat.yang@dsp.im (imacat), 2023/9/23
/**
 * @module components/Discover/Conformance/MoreModal
 *   Modal dialog showing detailed conformance check
 *   results with expandable activity sequences.
 */

import { ref, computed, watch, nextTick, useTemplateRef } from 'vue';
import { storeToRefs } from 'pinia';
import { useConformanceStore } from '@/stores/conformance';
import cytoscapeMapTrace from '@/module/cytoscapeMapTrace.js';

const props = defineProps(['listModal', 'listNo', 'traceId', 'firstCases', 'listTraces', 'taskSeq', 'cases', 'category']);
const emit = defineEmits(['closeModal']);

const conformanceStore = useConformanceStore();
const { infinite404 } = storeToRefs(conformanceStore);

// template ref
const cfmTrace = useTemplateRef('cfmTrace');

// data
const contentClass = ref('!bg-neutral-100 border-t border-neutral-300 h-full');
const showTraceId = ref(null);
const infiniteData = ref(null);
const maxItems = ref(false);
const infiniteFinish = ref(true); // 無限滾動是否載入完成
const startNum = ref(0);
const processMap = ref({
  nodes:[],
  edges:[],
});

// computed
const traceTotal = computed(() => {
  return traceList.value.length;
});

const traceList = computed(() => {
  const sum = props.listTraces.map(trace => trace.count).reduce((acc, cur) => acc + cur, 0);

  return props.listTraces.map(trace => {
    return {
      id: trace.id,
      value: Number((getPercentLabel(trace.count / sum))),
      count: trace.count.toLocaleString('en-US'),
      count_base: trace.count,
      ratio: getPercentLabel(trace.count / sum),
    };
  }).sort((x, y) => x.id - y.id);
});

const caseData = computed(() => {
  if(infiniteData.value !== null){
    const data = JSON.parse(JSON.stringify(infiniteData.value)); // 深拷貝原始 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;
  }
});

const columnData = computed(() => {
  const data = JSON.parse(JSON.stringify(props.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
watch(() => props.listModal, (newValue) => { // 第一次打開 Modal 要繪圖
  if(newValue) createCy();
});

watch(() => props.taskSeq, (newValue) => {
  if (newValue !== null) createCy();
});

watch(() => props.traceId, (newValue) => {
  // 當 traceId 屬性變化時更新 showTraceId
  showTraceId.value = newValue;
});

watch(showTraceId, (newValue, oldValue) => {
  const isScrollTop = document.querySelector('.infiniteTable');
  if(isScrollTop && typeof isScrollTop.scrollTop !== 'undefined') if(newValue !== oldValue) isScrollTop.scrollTop = 0;
});

watch(() => props.firstCases, (newValue) => {
  infiniteData.value = newValue;
});

watch(infinite404, (newValue) => {
  if (newValue === 404) maxItems.value = true;
});

// methods
/**
 * Number to percentage
 * @param   {number} val - The raw ratio value.
 * @returns {string} The formatted percentage string.
 */
function getPercentLabel(val){
  if((val * 100).toFixed(1) >= 100) return 100;
  else return parseFloat((val * 100).toFixed(1));
}
/**
 * set progress bar width
 * @param   {number} value - The percentage value.
 * @returns {string} The CSS width style string.
 */
function progressWidth(value){
  return `width:${value}%;`
}
/**
 * switch case data
 * @param {number} id case id
 */
async function switchCaseData(id) {
  if(id == showTraceId.value) return;
  infinite404.value = null;
  maxItems.value = false;
  startNum.value = 0;

  let result;
  if(props.category === 'issue') result = await conformanceStore.getConformanceTraceDetail(props.listNo, id, 0);
  else if(props.category === 'loop') result = await conformanceStore.getConformanceLoopsTraceDetail(props.listNo, id, 0);
  infiniteData.value = await result;
  showTraceId.value = id; // 放 getDetail 為了 case table 載入完再切換 showTraceId
}
/**
 * Assembles the trace element nodes data for Cytoscape rendering.
 */
function setNodesData(){
  // 避免每次渲染都重複累加
  processMap.value.nodes = [];
  // 將 api call 回來的資料帶進 node
  if(props.taskSeq !== null) {
    props.taskSeq.forEach((node, index) => {
      processMap.value.nodes.push({
        data: {
          id: index,
          label: node,
          backgroundColor: '#CCE5FF',
          bordercolor: '#003366',
          shape: 'round-rectangle',
          height: 80,
          width: 100
        }
      });
    });
  };
}
/**
 * Assembles the trace edge line data for Cytoscape rendering.
 */
function setEdgesData(){
  processMap.value.edges = [];
  if(props.taskSeq !== null) {
    props.taskSeq.forEach((edge, index) => {
      processMap.value.edges.push({
        data: {
          source: `${index}`,
          target: `${index + 1}`,
          lineWidth: 1,
          style: 'solid'
        }
      });
    });
  };
  // 關係線數量筆節點少一個
  processMap.value.edges.pop();
}
/**
 * create trace cytoscape's map
 */
function createCy(){
  nextTick(() => {
    const graphId = cfmTrace.value;

    setNodesData();
    setEdgesData();
    if(graphId !== null) cytoscapeMapTrace(processMap.value.nodes, processMap.value.edges, graphId);
  });
}
/**
 * Infinite scroll: loads more data.
 */
async function fetchData() {
  try {
    infiniteFinish.value = false;
    startNum.value += 20
    const result = await conformanceStore.getConformanceTraceDetail(props.listNo, showTraceId.value, startNum.value);
    infiniteData.value = await [...infiniteData.value, ...result];
    infiniteFinish.value = await true;
  } catch(error) {
    console.error('Failed to load data:', error);
  }
}
/**
 * Infinite scroll: listens for scroll reaching the bottom.
 * @param {Event} event - The scroll event.
 */
function handleScroll(event) {
  if(maxItems.value || infiniteData.value.length < 20 || infiniteFinish.value === false) return;

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

  if (overScrollHeight) fetchData();
}
</script>
<style scoped>
@reference "../../../assets/tailwind.css";
/* Progress bar color */
: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;
  white-space: nowrap;
}
:deep(.p-datatable .p-datatable-tbody > tr > td) {
  @apply border-neutral-500 !border-t-0 text-center
}
/* Center header title */
:deep(.p-column-header-content) {
  @apply justify-center
}
: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>
