<template>
  <!-- Sidebar: Switch data type -->
  <div class="flex flex-col justify-between py-4 w-14 h-screen-main absolute bottom-0 left-0 z-10"
    :class="sidebarLeftValue ? 'bg-neutral-50' : ''">
    <ul class="space-y-4 flex flex-col justify-center items-center">
      <li class="inline-flex items-center justify-center border border-neutral-500  rounded-full w-9 h-9 cursor-pointer bg-neutral-50 drop-shadow
        hover:border-primary" @click="sidebarView = !sidebarView" :class="{ 'border-primary': sidebarView }"
        v-tooltip="tooltip.sidebarView">
        <span class="material-symbols-outlined !text-2xl hover:text-primary p-1.5"
          :class="[sidebarView ? 'text-primary' : 'text-neutral-500']">
          track_changes
        </span>
      </li>
      <li class="inline-flex items-center justify-center border border-neutral-500  rounded-full w-9 h-9 cursor-pointer bg-neutral-50 drop-shadow
        hover:border-primary" @click="sidebarFilter = !sidebarFilter" :class="{ 'border-primary': sidebarFilter }"
        v-tooltip="tooltip.sidebarFilter">
        <span class="material-symbols-outlined !text-2xl hover:text-primary p-1.5"
          :class="[sidebarFilter ? 'text-primary' : 'text-neutral-500']" id="iconFilter">
          tornado
        </span>
      </li>
      <li class="inline-flex items-center justify-center border border-neutral-500  rounded-full w-9 h-9 cursor-pointer bg-neutral-50
        drop-shadow hover:border-primary" @click="sidebarTraces = !sidebarTraces"
        :class="{ 'border-primary': sidebarTraces }" v-tooltip="tooltip.sidebarTraces">
        <span class="material-symbols-outlined !text-2xl hover:text-primary p-1.5"
          :class="[sidebarTraces ? 'text-primary' : 'text-neutral-500']">
          rebase
        </span>
      </li>
    </ul>
  </div>

  <!-- Cytoscape Map -->
  <div class="min-w-full h-screen-main bg-neutral-50 -z-40">
    <div id="cy" class="min-w-full h-screen-main"></div>
  </div>

  <!-- Sidebar: State -->
  <div id='sidebar_state' class="bg-transparent py-4 w-14 h-screen-main z-10 bottom-0 right-0 absolute">
    <ul class="flex flex-col justify-center items-center">
      <li class="inline-flex items-center justify-center border border-neutral-500  rounded-full w-9 h-9 cursor-pointer
        bg-neutral-50 drop-shadow hover:border-primary" @click="sidebarState = !sidebarState"
        :class="{ 'border-primary': sidebarState }" id="iconState" v-tooltip.left="tooltip.sidebarState">
        <span class="material-symbols-outlined !text-2xl text-neutral-500 hover:text-primary p-1.5"
          :class="[sidebarState ? 'text-primary' : 'text-neutral-500']">
          info
        </span>
      </li>
    </ul>
  </div>

  <!-- Sidebar Model -->
  <SidebarView v-model:visible="sidebarView" @switch-map-type="switchMapType" @switch-curve-styles="switchCurveStyles"
    @switch-rank="switchRank" @switch-data-layer-type="switchDataLayerType"></SidebarView>
  <SidebarState v-model:visible="sidebarState" :insights="insights" :stats="stats"></SidebarState>
  <SidebarTraces v-model:visible="sidebarTraces" :cases="cases" @switch-Trace-Id="switchTraceId" ref="tracesView">
  </SidebarTraces>
  <SidebarFilter v-model:visible="sidebarFilter" :filterTasks="filterTasks" :filterStartToEnd="filterStartToEnd"
    :filterEndToStart="filterEndToStart" :filterTimeframe="filterTimeframe" :filterTrace="filterTrace"
    @submit-all="createCy(mapType)" @switch-Trace-Id="switchTraceId" ref="sidebarFilterRef"></SidebarFilter>
</template>

<script>
import { onBeforeMount, computed, } from 'vue';
import { storeToRefs } from 'pinia';
import { useRoute } from 'vue-router';
import LoadingStore from '@/stores/loading.js';
import AllMapDataStore from '@/stores/allMapData.js';
import ConformanceStore from '@/stores/conformance.js';
import cytoscapeMap from '@/module/cytoscapeMap.js';
import CytoscapeStore from '@/stores/cytoscapeStore';
import MapPathStore from '@/stores/mapPathStore';
import SidebarView from '@/components/Discover/Map/SidebarView.vue';
import SidebarState from '@/components/Discover/Map/SidebarState.vue';
import SidebarTraces from '@/components/Discover/Map/SidebarTraces.vue';
import SidebarFilter from '@/components/Discover/Map/SidebarFilter.vue';
import ImgCapsule1 from '@/assets/capsule1.svg';
import ImgCapsule2 from '@/assets/capsule2.svg';
import ImgCapsule3 from '@/assets/capsule3.svg';
import ImgCapsule4 from '@/assets/capsule4.svg';

const ImgCapsules = [ImgCapsule1, ImgCapsule2, ImgCapsule3, ImgCapsule4];

export default {
  setup() {
    const loadingStore = LoadingStore();
    const allMapDataStore = AllMapDataStore();
    const { isLoading } = storeToRefs(loadingStore);
    const route = useRoute();
    const { processMap, bpmn, stats, insights, traceId, traces, baseTraces, baseTraceId,
      filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe, filterTrace,
      temporaryData, isRuleData, ruleData, logId, baseLogId, createFilterId, cases,
      postRuleData
    } = storeToRefs(allMapDataStore);

    const cytoscapeStore = CytoscapeStore();

    const { setCurrentGraphId } = cytoscapeStore;

    const numberBeforeMapInRoute = computed(() => {
      // 取得當前路由的路徑
      const path = route.path;
      // 使用斜線分割路徑
      const segments = path.split('/');
      // 查找包含 'map' 的片段索引
      const mapIndex = segments.findIndex(segment => segment.includes('map'));
      if (mapIndex > 0) {
        // 定位到 'map' 片段的左邊片段
        const previousSegment = segments[mapIndex - 1];
        // 萃取左邊片段中的數字
        const match = previousSegment.match(/\d+/);
        return match ? match[0] : 'No number found';
      }
      return 'No map segment found';
    });

    onBeforeMount(() => {
      setCurrentGraphId(numberBeforeMapInRoute);
    });


    return {
      isLoading, processMap, bpmn, stats, insights, traceId, traces, baseTraces,
      baseTraceId, filterTasks, filterStartToEnd, filterEndToStart, filterTimeframe,
      filterTrace, logId, baseLogId, createFilterId, temporaryData, isRuleData,
      ruleData, allMapDataStore, cases, postRuleData,
      setCurrentGraphId,
    };
  },
  props: ['type', 'checkType', 'checkId', 'checkFileId'], // 來自 router 的 props
  components: {
    SidebarView,
    SidebarState,
    SidebarTraces,
    SidebarFilter,
  },
  data() {
    return {
      processMapData: {
        startId: 0,
        endId: 1,
        nodes: [],
        edges: [],
      },
      bpmnData: {
        startId: 0,
        endId: 1,
        nodes: [],
        edges: [],
      },
      cytoscapeGraph: null,
      curveStyle: 'unbundled-bezier', // unbundled-bezier | taxi
      mapType: 'processMap', // processMap | bpmn
      mapPathStore: MapPathStore(),
      dataLayerType: 'freq', // freq | duration
      dataLayerOption: 'total',
      rank: 'LR', // 直向 TB | 橫向 LR
      traceId: 1,
      sidebarView: false, // SideBar: Visualization Setting
      sidebarState: false, // SideBar: Summary & Insight
      sidebarTraces: false, // SideBar: Traces
      sidebarFilter: false, // SideBar: Filter
      infiniteFirstCases: null,
      startNodeId: -1,
      endNodeId: -1,
      tooltip: {
        sidebarView: {
          value: 'Visualization Setting',
          class: 'ml-1',
          pt: {
            text: 'text-[10px] p-1'
          }
        },
        sidebarTraces: {
          value: 'Trace',
          class: 'ml-1',
          pt: {
            text: 'text-[10px] p-1'
          }
        },
        sidebarFilter: {
          value: 'Filter',
          class: 'ml-1',
          pt: {
            text: 'text-[10px] p-1'
          }
        },
        sidebarState: {
          value: 'Summary',
          class: 'ml-1',
          pt: {
            text: 'text-[10px] p-1'
          }
        },
      }
    }
  },
  computed: {
    sidebarLeftValue: function () {
      const result = this.sidebarView === true || this.sidebarTraces === true || this.sidebarFilter === true;
      return result;
    }
  },
  watch: {
    sidebarView: function (newValue) {
      if (newValue) {
        this.sidebarFilter = false;
        this.sidebarTraces = false;
      }
    },
    sidebarFilter: function (newValue) {
      if (newValue) {
        this.sidebarView = false;
        this.sidebarState = false;
        this.sidebarTraces = false;
        this.sidebarState = false;
      }
    },
    sidebarTraces: function (newValue) {
      if (newValue) {
        this.sidebarView = false;
        this.sidebarState = false;
        this.sidebarFilter = false;
        this.sidebarState = false;
      }
    },
    sidebarState: function (newValue) {
      if (newValue) {
        this.sidebarFilter = false;
        this.sidebarTraces = false;
      }
    },
  },
  methods: {
    /**
     * switch map type
     * @param {string} type 'processMap' | 'bpmn'，可傳入以上任一。
     */
    async switchMapType(type) {
      this.mapType = type;
      this.createCy(type);
    },
    /**
     * switch curve style
     * @param {string} style 直角 'unbundled-bezier' | 'taxi'，可傳入以上任一。
     */
    async switchCurveStyles(style) {
      this.curveStyle = style;
      this.createCy(this.mapType);
    },
    /**
     * switch rank
     * @param {string} rank 直向 'TB' | 橫向 'LR'，可傳入以上任一。
     */
    async switchRank(rank) {
      this.rank = rank;
      this.createCy(this.mapType);
    },
    /**
     * switch Data Layoer Type or Option.
     * @param {string} type freq | duration
     * @param {string} option 下拉選單中的選項
     */
    async switchDataLayerType(type, option) {
      this.dataLayerType = type;
      this.dataLayerOption = option;
      this.createCy(this.mapType);
    },
    /**
     * switch trace id and data
     * @param {event} e input 傳入的事件
     */
    async switchTraceId(e) {
      if (e.id == this.traceId) return;
      // 超過 1000 筆要 loading 畫面
      this.isLoading = true; // 都要 loading 畫面
      this.traceId = e.id;
      await this.allMapDataStore.getTraceDetail();
      this.$refs.tracesView.createCy();
      this.isLoading = false;
    },
    /**
     * 將 element nodes 資料彙整
     * @param {object} type 'processMapData' | 'bpmnData'，可傳入以上任一。
     */
    setNodesData(mapData) {
      const mapType = this.mapType;
      const logFreq = {
        "total": "",
        "rel_freq": "",
        "average": "",
        "median": "",
        "max": "",
        "min": "",
        "cases": ""
      };
      const logDuration = {
        "total": "",
        "rel_duration": "",
        "average": "",
        "median": "",
        "max": "",
        "min": "",
      };
      // BPMN 才有 gateway 類別
      const gateway = {
        parallel: "+",
        exclusive: "x",
        inclusive: "o",
      };

      // 避免每次渲染都重複累加
      mapData.nodes = [];
      // 將 api call 回來的資料帶進 node
      this[mapType].vertices.forEach(node => {
        switch (node.type) {
          // add type of 'bpmn gateway' node
          case 'gateway':
            mapData.nodes.push({
              data: {
                id: node.id,
                type: node.type,
                label: gateway[node.gateway_type],
                height: 60,
                width: 60,
                backgroundColor: '#FFF',
                bordercolor: '#003366',
                shape: "diamond",
                freq: logFreq,
                duration: logDuration,
              }
            })
            break;
          // add type of 'event' node
          case 'event':
            if (node.event_type === 'start') {
              mapData.startId = node.id;
              this.startNodeId = node.id;
            }
            else if (node.event_type === 'end') {
              mapData.endId = node.id;
              this.endNodeId = node.id;
            }

            mapData.nodes.push({
              data: {
                id: node.id,
                type: node.type,
                label: node.event_type,
                height: 48,
                width: 48,
                backgroundColor: '#FFFFFF',
                bordercolor: '#0F172A',
                textColor: '#FF3366',
                shape: "ellipse",
                freq: logFreq,
                duration: logDuration,
              }
            });
            break;
          // add type of 'activity' node
          default:
            mapData.nodes.push({
              data: {
                id: node.id,
                type: node.type,
                label: node.label,
                height: 48,
                width: 216,
                textColor: '#0F172A',
                backgroundColor: 'rgba(0, 0, 0, 0)',
                borderradius: 999,
                shape: "round-rectangle",
                freq: node.freq,
                duration: node.duration,
                backgroundOpacity: 0,
                borderOpacity: 0,
              }
            })
            break;
        }
      });
    },
    /**
     * 將 element edges 資料彙整
     * @param {object} type 'processMapData' | 'bpmnData'，可傳入以上任一。
     */
    setEdgesData(mapData) {
      const mapType = this.mapType;
      //add event duration is empty
      const logDuration = {
        "total": "",
        "rel_duration": "",
        "average": "",
        "median": "",
        "max": "",
        "min": "",
        "cases": ""
      };

      mapData.edges = [];
      this[mapType].edges.forEach(edge => {
        mapData.edges.push({
          data: {
            source: edge.tail,
            target: edge.head,
            freq: edge.freq,
            duration: edge.duration === null ? logDuration : edge.duration,
            // Don't know why but tail is related to start and head is related to end
            edgeStyle: edge.tail === this.startNodeId || edge.head === this.endNodeId ? 'dotted' : 'solid',
            lineWidth: 1,
          },
        });
      });
    },
    /**
     * create cytoscape's map
     * @param {string} type this.mapType 'processMap' | 'bpmn'，可傳入以上任一。
     */
    async createCy(type) {
      const graphId = document.getElementById('cy');
      const mapData = type === 'processMap' ? this.processMapData : this.bpmnData;

      if (this[type].vertices.length !== 0) {
        this.setNodesData(mapData);
        this.setEdgesData(mapData);
        this.setActivityBgImage(mapData);
        this.cytoscapeGraph = await cytoscapeMap(mapData, this.dataLayerType, this.dataLayerOption, this.curveStyle, this.rank, graphId);
        const processOrBPMN = this.mapType === 'processMap' ? 'process' : 'bpmn';
        const curveType = this.curveStyle === 'taxi' ? 'elbow' : 'curved';
        const directionType = this.rank === 'LR' ? 'horizontal' : 'vertical';
        await this.mapPathStore.setCytoscape(this.cytoscapeGraph, processOrBPMN, curveType, directionType);
      };
    },
    setActivityBgImage(mapData) {
      const nodes = mapData.nodes;
      // 一組有多少個activities
      const groupSize = Math.floor(nodes.length / ImgCapsules.length);
      let nodeOptionArr = [];
      const leveledGroups = []; // 每一個level會使用不同的膠囊圖片
      // 設定除了 start, end 的 node 顏色
      // 找出 type activity's node
      const activityNodeArray = nodes.filter(node => node.data.type === 'activity');
      // 找出除了 start, end 以外所有的 node 的 option value
      activityNodeArray.forEach(node => nodeOptionArr.push(node.data[this.dataLayerType][this.dataLayerOption]));
      // 將node的option值從小到大排序(映對色階淺到深)
      nodeOptionArr = nodeOptionArr.sort((a, b) => a - b);
      for (let i = 0; i < ImgCapsules.length; i++) {
        const startIdx = i * groupSize;
        const endIdx = (i === ImgCapsules.length - 1) ? activityNodeArray.length : startIdx + groupSize;
        leveledGroups.push(nodeOptionArr.slice(startIdx, endIdx));
      }
      for (let level = 0; level < leveledGroups.length; level++) {
        leveledGroups[level].forEach(option => {
          // 考慮可能有名次一樣的情形
          const curNodes = activityNodeArray.filter(activityNode => activityNode.data[this.dataLayerType][this.dataLayerOption] === option);
          curNodes.forEach(curNode => {
            curNode.data = {
              ...curNode.data,
              nodeImageUrl: ImgCapsules[level],
              level,
            };
          });
        });
      }
    },
  },
  async created() {
    const routeParams = this.$route.params;
    const file = this.$route.meta.file;
    const isCheckPage = this.$route.name.includes('Check');

    // 先 loading 再執行以下程式
    this.isLoading = true;
    // Log 檔前往 Map Log 頁, Filter 檔前往 Map Filter 頁
    switch (routeParams.type) {
      case 'log':
        if (!isCheckPage) {
          this.logId = await routeParams.fileId;
          this.baseLogId = await routeParams.fileId;
        } else {
          this.logId = await file.parent.id;
          this.baseLogId = await file.parent.id;
        }
        break;
      case 'filter':
        if (!isCheckPage) {
          this.createFilterId = await routeParams.fileId;
        } else {
          this.createFilterId = await file.parent.id;
        }
        // 取得 logID 和上次儲存的 Funnel
        await this.allMapDataStore.fetchFunnel(this.createFilterId);
        this.isRuleData = await Array.from(this.temporaryData);
        this.ruleData = await this.isRuleData.map(e => this.$refs.sidebarFilterRef.setRule(e));
        break;
    }
    // 取得 logId 後才 call api
    await this.allMapDataStore.getAllMapData();
    await this.allMapDataStore.getAllTrace();

    // log、filter 檔切換過程中， trace id 不同，將初始 trace id 設定為該檔案的 trace 幣一筆資料的 id。
    this.traceId = await this.traces[0]?.id;
    this.baseTraceId = await this.baseTraces[0]?.id;
    await this.createCy(this.mapType);
    await this.allMapDataStore.getFilterParams();
    await this.allMapDataStore.getTraceDetail();

    // 執行完後才取消 loading
    this.isLoading = false;
    // 存檔 Modal 打開時，側邊欄要關閉
    this.$emitter.on('saveModal', boolean => {
      this.sidebarView = boolean;
      this.sidebarFilter = boolean;
      this.sidebarTraces = boolean;
      this.sidebarState = boolean;
    });
    this.$emitter.on('leaveFilter', boolean => {
      this.sidebarView = boolean;
      this.sidebarFilter = boolean;
      this.sidebarTraces = boolean;
      this.sidebarState = boolean;
    });
  },
  beforeUnmount() {
    this.logId = null;
    this.createFilterId = null;
    this.tempFilterId = null;
    this.temporaryData = [];
    this.postRuleData = [];
    this.ruleData = [];
  },
  async beforeRouteEnter(to, from, next) {
    const isCheckPage = to.name.includes('Check');

    if (isCheckPage) {
      const conformanceStore = ConformanceStore();
      switch (to.params.type) {
        case 'log':
          conformanceStore.conformanceLogCreateCheckId = to.params.fileId;
          break;
        case 'filter':
          conformanceStore.conformanceFilterCreateCheckId = to.params.fileId;
          break;
      }
      await conformanceStore.getConformanceReport(true);
      to.meta.file = conformanceStore.routeFile; // 將 file data 存到 route
    }
    next();
  }
}
</script>
