<!-- Sidebar: Switch data type -->
<template>
  <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="tracesViewRef">
  </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="sidebarFilterRefComp"></SidebarFilter>
</template>

<script>
import { useConformanceStore } from '@/stores/conformance';

export default {
  async beforeRouteEnter(to, from, next) {
    const isCheckPage = to.name.includes('Check');

    if (isCheckPage) {
      const conformanceStore = useConformanceStore();
      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;
    }
    next();
  }
}
</script>

<script setup>
import { ref, computed, watch, onBeforeMount, onBeforeUnmount } from 'vue';
import { useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useLoadingStore } from '@/stores/loading';
import { useAllMapDataStore } from '@/stores/allMapData';
import { useConformanceStore } from '@/stores/conformance';
import cytoscapeMap from '@/module/cytoscapeMap.js';
import { useCytoscapeStore } from '@/stores/cytoscapeStore';
import { useMapPathStore } from '@/stores/mapPathStore';
import emitter from '@/utils/emitter';
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];

const props = defineProps(['type', 'checkType', 'checkId', 'checkFileId']);

const route = useRoute();

// Stores
const loadingStore = useLoadingStore();
const allMapDataStore = useAllMapDataStore();
const { isLoading } = storeToRefs(loadingStore);
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 = useCytoscapeStore();
const { setCurrentGraphId } = cytoscapeStore;
const mapPathStore = useMapPathStore();

const numberBeforeMapInRoute = computed(() => {
  const path = route.path;
  const segments = path.split('/');
  const mapIndex = segments.findIndex(segment => segment.includes('map'));
  if (mapIndex > 0) {
    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);
});

// Data
const processMapData = ref({
  startId: 0,
  endId: 1,
  nodes: [],
  edges: [],
});
const bpmnData = ref({
  startId: 0,
  endId: 1,
  nodes: [],
  edges: [],
});
const cytoscapeGraph = ref(null);
const curveStyle = ref('unbundled-bezier');
const mapType = ref('processMap');
const dataLayerType = ref('freq');
const dataLayerOption = ref('total');
const rank = ref('LR');
const localTraceId = ref(1);
const sidebarView = ref(false);
const sidebarState = ref(false);
const sidebarTraces = ref(false);
const sidebarFilter = ref(false);
const infiniteFirstCases = ref(null);
const startNodeId = ref(-1);
const endNodeId = ref(-1);
const tracesViewRef = ref(null);
const sidebarFilterRefComp = ref(null);

const 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
const sidebarLeftValue = computed(() => {
  return sidebarView.value === true || sidebarTraces.value === true || sidebarFilter.value === true;
});

// Watch
watch(sidebarView, (newValue) => {
  if (newValue) {
    sidebarFilter.value = false;
    sidebarTraces.value = false;
  }
});

watch(sidebarFilter, (newValue) => {
  if (newValue) {
    sidebarView.value = false;
    sidebarState.value = false;
    sidebarTraces.value = false;
    sidebarState.value = false;
  }
});

watch(sidebarTraces, (newValue) => {
  if (newValue) {
    sidebarView.value = false;
    sidebarState.value = false;
    sidebarFilter.value = false;
    sidebarState.value = false;
  }
});

watch(sidebarState, (newValue) => {
  if (newValue) {
    sidebarFilter.value = false;
    sidebarTraces.value = false;
  }
});

// Methods
async function switchMapType(type) {
  mapType.value = type;
  createCy(type);
}

async function switchCurveStyles(style) {
  curveStyle.value = style;
  createCy(mapType.value);
}

async function switchRank(rankValue) {
  rank.value = rankValue;
  createCy(mapType.value);
}

async function switchDataLayerType(type, option) {
  dataLayerType.value = type;
  dataLayerOption.value = option;
  createCy(mapType.value);
}

async function switchTraceId(e) {
  if (e.id == traceId.value) return;
  isLoading.value = true;
  traceId.value = e.id;
  await allMapDataStore.getTraceDetail();
  tracesViewRef.value.createCy();
  isLoading.value = false;
}

function setNodesData(mapData) {
  const mapTypeVal = mapType.value;
  const logFreq = {
    "total": "",
    "rel_freq": "",
    "average": "",
    "median": "",
    "max": "",
    "min": "",
    "cases": ""
  };
  const logDuration = {
    "total": "",
    "rel_duration": "",
    "average": "",
    "median": "",
    "max": "",
    "min": "",
  };
  const gateway = {
    parallel: "+",
    exclusive: "x",
    inclusive: "o",
  };

  mapData.nodes = [];
  const mapSource = mapTypeVal === 'processMap' ? processMap.value : bpmn.value;
  mapSource.vertices.forEach(node => {
    switch (node.type) {
      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;
      case 'event':
        if (node.event_type === 'start') {
          mapData.startId = node.id;
          startNodeId.value = node.id;
        }
        else if (node.event_type === 'end') {
          mapData.endId = node.id;
          endNodeId.value = 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;
      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;
    }
  });
}

function setEdgesData(mapData) {
  const mapTypeVal = mapType.value;
  const logDuration = {
    "total": "",
    "rel_duration": "",
    "average": "",
    "median": "",
    "max": "",
    "min": "",
    "cases": ""
  };

  mapData.edges = [];
  const mapSource = mapTypeVal === 'processMap' ? processMap.value : bpmn.value;
  mapSource.edges.forEach(edge => {
    mapData.edges.push({
      data: {
        source: edge.tail,
        target: edge.head,
        freq: edge.freq,
        duration: edge.duration === null ? logDuration : edge.duration,
        edgeStyle: edge.tail === startNodeId.value || edge.head === endNodeId.value ? 'dotted' : 'solid',
        lineWidth: 1,
      },
    });
  });
}

async function createCy(type) {
  const graphId = document.getElementById('cy');
  const mapData = type === 'processMap' ? processMapData.value : bpmnData.value;
  const mapSource = type === 'processMap' ? processMap.value : bpmn.value;

  if (mapSource.vertices.length !== 0) {
    setNodesData(mapData);
    setEdgesData(mapData);
    setActivityBgImage(mapData);
    cytoscapeGraph.value = await cytoscapeMap(mapData, dataLayerType.value, dataLayerOption.value, curveStyle.value, rank.value, graphId);
    const processOrBPMN = mapType.value === 'processMap' ? 'process' : 'bpmn';
    const curveType = curveStyle.value === 'taxi' ? 'elbow' : 'curved';
    const directionType = rank.value === 'LR' ? 'horizontal' : 'vertical';
    await mapPathStore.setCytoscape(cytoscapeGraph.value, processOrBPMN, curveType, directionType);
  };
}

function setActivityBgImage(mapData) {
  const nodes = mapData.nodes;
  const groupSize = Math.floor(nodes.length / ImgCapsules.length);
  let nodeOptionArr = [];
  const leveledGroups = [];
  const activityNodeArray = nodes.filter(node => node.data.type === 'activity');
  activityNodeArray.forEach(node => nodeOptionArr.push(node.data[dataLayerType.value][dataLayerOption.value]));
  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[dataLayerType.value][dataLayerOption.value] === option);
      curNodes.forEach(curNode => {
        curNode.data = {
          ...curNode.data,
          nodeImageUrl: ImgCapsules[level],
          level,
        };
      });
    });
  }
}

// Created logic
(async () => {
  const routeParams = route.params;
  const file = route.meta.file;
  const isCheckPage = route.name.includes('Check');

  isLoading.value = true;
  switch (routeParams.type) {
    case 'log':
      if (!isCheckPage) {
        logId.value = await routeParams.fileId;
        baseLogId.value = await routeParams.fileId;
      } else {
        logId.value = await file.parent.id;
        baseLogId.value = await file.parent.id;
      }
      break;
    case 'filter':
      if (!isCheckPage) {
        createFilterId.value = await routeParams.fileId;
      } else {
        createFilterId.value = await file.parent.id;
      }
      await allMapDataStore.fetchFunnel(createFilterId.value);
      isRuleData.value = await Array.from(temporaryData.value);
      ruleData.value = await isRuleData.value.map(e => sidebarFilterRefComp.value.setRule(e));
      break;
  }
  await allMapDataStore.getAllMapData();
  await allMapDataStore.getAllTrace();

  traceId.value = await traces.value[0]?.id;
  baseTraceId.value = await baseTraces.value[0]?.id;
  await createCy(mapType.value);
  await allMapDataStore.getFilterParams();
  await allMapDataStore.getTraceDetail();

  isLoading.value = false;
  emitter.on('saveModal', boolean => {
    sidebarView.value = boolean;
    sidebarFilter.value = boolean;
    sidebarTraces.value = boolean;
    sidebarState.value = boolean;
  });
  emitter.on('leaveFilter', boolean => {
    sidebarView.value = boolean;
    sidebarFilter.value = boolean;
    sidebarTraces.value = boolean;
    sidebarState.value = boolean;
  });
})();

onBeforeUnmount(() => {
  logId.value = null;
  createFilterId.value = null;
  temporaryData.value = [];
  postRuleData.value = [];
  ruleData.value = [];
});
</script>
