<template>
  <Sidebar :visible="sidebarFilter" :closeIcon="'pi pi-chevron-left'" :modal="false" position="left" :dismissable="true" :baseZIndex="15" class="!w-11/12 !bg-neutral-100" @hide="hide()">
    <template #header>
      <ul class="flex space-x-4">
        <li class="h1 border-r-2 border-neutral-300 pr-4 cursor-pointer hover:text-neutral-900 hover:duration-700" @click="switchTab('filter')" :class="tab === 'filter'? 'text-neutral-900': 'text-neutral-500'" id="tabFilter">Filter</li>
        <li class="h1 border-r-2 border-neutral-300 pr-4 cursor-pointer hover:text-neutral-900 hover:duration-700" @click="switchTab('funnel')" :class="tab === 'funnel'? 'text-neutral-900': 'text-neutral-500'" id="tabFunnel">Funnel</li>
      </ul>
    </template>
    <!-- header: filter -->
    <div v-if="tab === 'filter'" class="pt-4 flex w-full h-full text-neutral-900">
      <!-- title: filter silect -->
      <div class="space-y-2 mr-4 w-48 text-sm">
        <div>
          <p class="h2">Filter Type</p>
          <div v-for="(item, index) in selectFilter['Filter Type']" :key="index">
            <RadioButton v-model="selectValue[0]" :inputId="item + index" name="Filter Type" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div v-show="selectValue[0] === 'Sequence'">
          <p class="h2">Activity Sequence</p>
          <div v-for="(item, index) in selectFilter['Activity Sequence']" :key="index">
            <RadioButton v-model="selectValue[1]" :inputId="item + index" name="Activity Sequence" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div v-show="selectValue[0] === 'Sequence' && selectValue[1] === 'Start activity / End activity'">
          <p class="h2">Start & End</p>
          <div v-for="(item, index) in selectFilter['Start & End']" :key="index">
            <RadioButton v-model="selectValue[2]" :inputId="item + index" name="Start & End" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div v-show="selectValue[0] === 'Sequence' && selectValue[1] === 'Sequence'">
          <p class="h2">Mode</p>
          <div v-for="(item, index) in selectFilter['Mode']" :key="index">
            <RadioButton v-model="selectValue[3]" :inputId="item + index" name="Mode" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div v-show="selectValue[0] === 'Attributes'">
          <p class="h2">Mode</p>
          <div v-for="(item, index) in selectFilter['ModeAtt']" :key="index">
            <RadioButton v-model="selectValue[4]" :inputId="item + index" name="ModeAtt" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div>
          <p class="h2">Refine</p>
          <div v-for="(item, index) in selectFilter['Refine']" :key="index">
            <RadioButton v-model="selectValue[5]" :inputId="item + index" name="Refinee" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
        <div v-show="selectValue[0] === 'Timeframes'">
          <p class="h2">Containment</p>
          <div v-for="(item, index) in selectFilter['Containment']" :key="index">
            <RadioButton v-model="selectValue[6]" :inputId="item + index" name="Containment" :value="item" class="mb-1 mr-2"/>
            <label :for="item + index">{{ item }}</label>
          </div>
        </div>
      </div>
      <!-- Fiter content -->
      <div class="w-[calc(100%_-_208px)] h-full">

        <!-- Filter titles -->
        <div class="space-y-2 w-full h-[calc(100%_-_48px)]">
          <!-- title: Activity Select  -->
          <div class="w-full h-[calc(100%_-_40px)]" v-if="selectValue[0] === 'Sequence'">
            <p class="h2 ml-1">Activity Select</p>
            <!-- Filter task Data-->
            <ActOccCase v-if="selectValue[0] === 'Sequence' && selectValue[1] === 'Have activity(s)'" :tableTitle="'Activity List'" :tableData="filterAllTaskData" :tableSelect="selectFilterTask" :progressWidth ="progressWidth" @on-row-select="onRowAct"></ActOccCase>
            <!-- Filter Start Data -->
            <ActOcc v-if="selectValue[0] === 'Sequence' && selectValue[1] === 'Start activity / End activity' && selectValue[2] === 'Start'" :tableTitle="'Start activity'" :tableData="filterStartData" :tableSelect="selectFilterStart" :progressWidth ="progressWidth" @on-row-select="onRowStart"></ActOcc>
            <!-- Filter End Data -->
            <ActOcc v-if="selectValue[0] === 'Sequence' && selectValue[1] === 'Start activity / End activity' && selectValue[2] === 'End'" :tableTitle="'End activity'" :tableData="filterEndData" :tableSelect="selectFilterEnd" :progressWidth ="progressWidth" @on-row-select="onRowEnd"></ActOcc>
            <!-- Filter Start And End Data -->
            <div v-if="selectValue[0] === 'Sequence' && selectValue[1] === 'Start activity / End activity' && selectValue[2] === 'Start & End'" class="flex justify-between items-center w-full h-full space-x-4 ">
              <ActOcc :tableTitle="'Start activity'" :tableData="filterStartToEndData" :tableSelect="selectFilterStartToEnd" :progressWidth ="progressWidth" class="w-1/2" @on-row-select="startRow"></ActOcc>
              <ActOcc :tableTitle="'End activity'" :tableData="filterEndToStartData" :tableSelect="selectFilterEndToStart" :progressWidth ="progressWidth" class="w-1/2" @on-row-select="endRow"></ActOcc>
            </div>
            <!-- Filter Sequence -->
            <div v-if="selectValue[0] === 'Sequence' && selectValue[1] === 'Sequence'" class="flex justify-between items-center w-full h-full space-x-4">
              <ActAndSeq :filterTaskData="filterTaskData" :progressWidth ="progressWidth" :listSeq="listSeq" @update:listSeq="onUpdateListSeq"></ActAndSeq>
            </div>
          </div>
          <!-- title: Trace -->
          <Trace v-if="selectValue[0] === 'Trace'" ref="filterTraceView"></Trace>
          <!-- title: Timeframes -->
          <Timeframes v-if="selectValue[0] === 'Timeframes'"></Timeframes>
        </div>

        <!-- Button -->
        <div class="float-right space-x-4 px-4 py-2">
          <button type="button"  class="btn btn-sm btn-neutral" @click="reset">Clear</button>
          <button type="button" class="btn btn-sm btn-neutral" @click="submit">Apply</button>
        </div>
      </div>
    </div>
    <!-- header: funnel -->
    <Funnel v-if="tab === 'funnel'" @submit-all="sumbitAll"></Funnel>
  </Sidebar>
</template>

<script>
import { storeToRefs } from 'pinia';
import LoadingStore from '@/stores/loading.js';
import AllMapDataStore from '@/stores/allMapData.js';
import ActOccCase from '@/components/Discover/Map/Filter/ActOccCase.vue';
import ActOcc from '@/components/Discover/Map/Filter/ActOcc.vue';
import ActAndSeq from '@/components/Discover/Map/Filter/ActAndSeq.vue';
import Funnel from '@/components/Discover/Map/Filter/Funnel.vue';
import Trace from '@/components/Discover/Map/Filter/Trace.vue';
import Timeframes from '@/components/Discover/Map/Filter/Timeframes.vue';
import getMoment from 'moment';

export default {
  props: ['sidebarFilter', 'filterTasks', 'filterStartToEnd', 'filterEndToStart', 'filterTimeframe', 'filterTrace'],
  setup() {
    const loadingStore = LoadingStore();
    const allMapDataStore = AllMapDataStore();
    const { isLoading } = storeToRefs(loadingStore);
    const { hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, selectTimeFrame } = storeToRefs(allMapDataStore);

    return { isLoading, hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, allMapDataStore, selectTimeFrame }
  },
  data() {
    return {
      selectFilter: {
        // 'Filter Type': ['Sequence', 'Attributes', 'Trace', 'Timeframes'],
        'Filter Type': ['Sequence', 'Trace', 'Timeframes'],
        'Activity Sequence':['Have activity(s)', 'Start activity / End activity', 'Sequence'],
        'Start & End': ['Start', 'End', 'Start & End'],
        'Mode': ['Directly follows', 'Eventually follows'],
        'ModeAtt': ['Case', 'Activity'],
        'Refine': ['Include', 'Exclude'],
        'Containment': ['Contained in', 'Started in', 'Ended in', 'Active in'],
      },
      tab: 'filter', // filter | funnel
      selectValue: {
        0: 'Sequence',
        1: 'Have activity(s)',
        2: 'Start',
        3: 'Directly follows',
        4: 'Case',
        5: 'Include',
        6: 'Contained in',
      },
      selectFilterTask: null,
      selectFilterStart: null,
      selectFilterEnd: null,
      selectFilterStartToEnd: null,
      selectFilterEndToStart: null,
      listSeq: [],
      //若第一次選擇 start, 則 end 連動改變，若第一次選擇 end, 則 start 連動改變
      isStartSelected: null,
      isEndSelected: null,
      isActAllTask: true,
      rowData: [],
    }
  },
  components: {
    ActOccCase,
    ActOcc,
    ActAndSeq,
    Funnel,
    Trace,
    Timeframes,
  },
  computed: {
    // All Task
    filterAllTaskData: function() {
      return this.setHaveAct([...this.filterTasks]);
    },
    // Act And Seq
    filterTaskData: function() {
      return this.isActAllTask? this.setHaveAct([...this.filterTasks]) : this.filterTaskData;
    },
    // Start and End Task
    filterStartData: function() {
      return this.setActData(this.filterStartToEnd);
    },
    filterEndData: function() {
      return this.setActData(this.filterEndToStart);
    },
    filterStartToEndData: function() {
      return this.isEndSelected ? this.setStartAndEndData(this.filterEndToStart, this.rowData, 'sources') : this.setActData(this.filterStartToEnd);
    },
    filterEndToStartData: function() {
      return this.isStartSelected ? this.setStartAndEndData(this.filterStartToEnd, this.rowData, 'sinks') : this.setActData(this.filterEndToStart);
    },
  },
  methods: {
    /**
     * @param {string} switch Summary or Insight
     */
     switchTab(tab) {
      this.tab = tab;
    },
    /**
     * Number to percentage
     * @param   {number} val
     * @returns {string}     轉換完成的百分比字串
     */
     getPercentLabel(val){
      return (val * 100 === 100) ? `${val * 100}%` : `${(val * 100).toFixed(1)}%`;
    },
    /**
     * set progress bar width
     * @param   {number} value
     * @returns {string}      樣式的寬度設定
     */
     progressWidth(value){
      return `width:${value}%;`
    },
    //設定 Have activity(s) 內容
    /**
     * @param {array} data filterTaskData
     */
    setHaveAct(data){
      return data.map(task => {
        return {
          label: task.label,
          occ_value: Number(task.occurrence_ratio * 100),
          occurrences: Number(task.occurrences).toLocaleString('en-US'),
          occurrence_ratio: this.getPercentLabel(task.occurrence_ratio),
          case_value: Number(task.case_ratio * 100),
          cases: task.cases.toLocaleString('en-US'),
          case_ratio: this.getPercentLabel(task.case_ratio),
        };
      }).sort((x, y) => y.occurrences - x.occurrences);
    },
    // 調整 filterStartData / filterEndData / filterStartToEndData / filterEndToStartData 的內容
    /**
     * @param {array} array filterStartToEnd / filterEndToStart
     */
    setActData(array) {
      let list = [];
      array.forEach((task, index) => {
        let data = {
          label: task.label,
          occ_value: Number(task.occurrence_ratio * 100),
          occurrences: Number(task.occurrences).toLocaleString('en-US'),
          occurrence_ratio: this.getPercentLabel(task.occurrence_ratio),
        };
        list.push(data);
      });
      return list;
    },
    /**
     * @param {array} select select Have activity(s) rows
     */
    onRowAct(select){
      this.selectFilterTask = select;
    },
    /**
     * @param {object} e select Start rows
     */
     onRowStart(e){
      this.selectFilterStart = e.data;
    },
    /**
     * @param {object} e select End rows
     */
     onRowEnd(e){
      this.selectFilterEnd = e.data;
    },
    /**
     * @param {array} e Update List Seq
     */
     onUpdateListSeq(listSeq) {
       this.listSeq = listSeq;
       this.isActAllTask = false;
     },
    // 在 Start & End 若第一次選擇 start, 則 end 連動改變，若第一次選擇 end, 則 start 連動改變
    /**
     * @param {object} e object contains selected row's data
     */
    startRow(e){
      this.selectFilterStartToEnd = e.data;
      if(this.isStartSelected === null || this.isStartSelected === true){
        this.isStartSelected = true;
        this.isEndSelected = false;
        this.rowData = e.data;
      }
    },
    endRow(e) {
      this.selectFilterEndToStart = e.data;
      if(this.isEndSelected === null || this.isEndSelected === true){
        this.isEndSelected = true;
        this.isStartSelected = false;
        this.rowData = e.data;
      }
    },
    // 重新設定連動的 filterStartToEndData / filterEndToStartData 內容
    /**
     * @param {array} eventData  Start or End List
     * @param {object} rowData 所選擇的 row's data
     * @param {string} event sinks / sources
     */
    setStartAndEndData(eventData, rowData, event){
      const filterData = event === 'sinks' ? this.filterEndToStart : this.filterStartToEnd;
      const relatedItems = eventData
        .find(task => task.label === rowData.label)
        ?.[event]?.filter(item => filterData.some(ele => ele.label === item))
        ?.map(item => filterData.find(ele => ele.label === item));

      if (!relatedItems) return [];
      return relatedItems.map(item => ({
        label: item.label,
        occ_value: Number(item.occurrence_ratio * 100),
        occurrences: Number(item.occurrences).toLocaleString('en-US'),
        occurrence_ratio: this.getPercentLabel(item.occurrence_ratio),
      }));
    },
    /**
     * @param {object} e task's object
     */
    setRule(e) {
      let label, type;
      const includeStr = e.is_exclude?" Exclude ":" Include ";
      let containmentMap = {
        'occurred-in' : 'Contained in',
        'started-in' : 'Started in',
        'completed-in' : 'Ended in',
        'occurred-around' : 'Active in'
      };

      switch(e.type){
        case "contains-task":
          label = `${includeStr} ${e.task}`
          type = "Sequence"
          break
        case "starts-with":
          label = `Start with ${e.task} ${includeStr}`
          type = "Sequence"
          break
        case "ends-with":
          label = `End with ${e.task} ${includeStr}`
          type = "Sequence"
          break
        case "start-end":
          label = `Start with ${e.starts_with}, End with ${e.ends_with} ${includeStr}`
          type = "Sequence"
          break
        case "directly-follows":
          label = `Directly-follows ${e.task_seq.join(' -> ')}${includeStr}`
          type = "Sequence"
          break
        case "eventually-follows":
          label = `Eventually-follows ${e.task_seq.join(' -> ')}${includeStr}`
          type = "Sequence"
          break
        case "occurred-in":
        case "started-in":
        case "completed-in":
        case "occurred-around":
          label = `${containmentMap[e.type]} from ${getMoment(e.start).format("YYYY-MM-DD HH:mm:ss")} to ${getMoment(e.end).format("YYYY-MM-DD HH:mm:ss")} ${includeStr}`
          type = "Timeframe"
          break
        case "trace-freq":
          label = `from #${e.lower} to #${e.upper} ${includeStr}`
          type = "Trace"
          break
      };
      return {
        type,
        label,
        toggle: true,
      };
    },
    /**
     * @param {boolean} massage true | false 清空選項
     */
    reset(massage) {
      // Sequence
      this.selectFilterTask = null;
      this.selectFilterStart = null;
      this.selectFilterEnd = null;
      this.selectFilterStartToEnd = null;
      this.selectFilterEndToStart = null;
      this.listSeq = [];
      this.isStartSelected = null;
      this.isEndSelected = null;
      this.isActAllTask = true;
      // Timeframes
      this.selectTimeFrame = [];
      // Trace
      if (this.$refs.filterTraceView) {
        this.$refs.filterTraceView.showTraceId = null;
        this.$refs.filterTraceView.selectArea = [0, this.$refs.filterTraceView.traceTotal];
      };
      // 成功訊息
      massage ? this.$toast.success('Reset Success.') : null;
    },
    // header:Filter 發送選取的資料
    async submit(){
      let data;
      let sele = this.selectValue;
      let isExclude = sele[5] === 'Exclude' ? true : false;
      let containmentMap = {
        'Contained in': 'occurred-in',
        'Started in': 'started-in',
        'Ended in': 'completed-in',
        'Active in': 'occurred-around'
      };

      // Filter Type 選 Sequence 的行為
      // 若陣列為空，則跳出警告訊息
      if(sele[0] === 'Sequence'){
        if(sele[1] === 'Have activity(s)'){ // Activity Sequence 選 Have activity(s) 的行為
          if(!this.selectFilterTask?.length) return this.$toast.error('Not selected');
          else {
            // 將多選的 task 拆成一包包 obj
            data = this.selectFilterTask.map(task => {
              return {
                type : 'contains-task',
                task : task.label,
                is_exclude : isExclude,
              }
            })
          };
        }else if(sele[1] === 'Start activity / End activity') { // Activity Sequence 選 Start activity / End activity 的行為
          if(sele[2] === 'Start') {
            if(this.selectFilterStart === null || this.selectFilterStart.length === 0) return this.$toast.error('Not selected');
            else {
              data = {
                type: 'starts-with',
                task: this.selectFilterStart.label,
                is_exclude: isExclude,
              }
            };
          }else if(sele[2] === 'End') {
            if(this.selectFilterEnd === null || this.selectFilterEnd.length === 0) return this.$toast.error('Not selected');
            else {
              data = {
                type: 'ends-with',
                task: this.selectFilterEnd.label,
                is_exclude: isExclude,
              }
            };
          }else if(sele[2] === 'Start & End') {
            if(this.selectFilterStartToEnd === null || this.selectFilterStartToEnd.length === 0 || this.selectFilterEndToStart === null || this.selectFilterEndToStart.length === 0 ) return this.$toast.error('Both Start and End must be selected.');
            else {
              data = {
                type: 'start-end',
                starts_with: this.selectFilterStartToEnd.label,
                ends_with: this.selectFilterEndToStart.label,
                is_exclude: isExclude,
              }
            }
          };
        }else if(sele[1] === 'Sequence'){ // Activity Sequence 選 Sequence 的行為
          if(this.listSeq.length < 2) return this.$toast.error('Select two or more.');
          else {
            data = {
              type: sele[3] === 'Directly follows' ? 'directly-follows' : 'eventually-follows',
              task_seq: this.listSeq.map(task => task.label),
              is_exclude: isExclude,
            }
          };
        }
      } else if(sele[0] === 'Timeframes'){ // Filter Type 選 Timeframes 的行為
        data = {
          type: containmentMap[sele[6]],
          start: this.selectTimeFrame[0],
          end: this.selectTimeFrame[1],
          is_exclude: isExclude,
        }
      } else if(sele[0] === 'Trace'){ // Filter Type 選 Trace 的行為
        data = {
          type: 'trace-freq',
          lower: this.$refs.filterTraceView.selectArea[0]+1,
          upper: this.$refs.filterTraceView.selectArea[1],
          is_exclude: isExclude,
        }
      }
      // 將資料指向 Vue data 雙向綁定
      const postData = Array.isArray(data) ? data : [data];

      // 快速檢查每一 filter 規則是否為空集合
      this.postRuleData = postData;
      await this.allMapDataStore.checkHasResult();

      // 有 Data 就加進 Funnel，沒有 Data 不加進 Funnel 和跳錯誤訊息
      if(this.hasResultRule === null) return;
      else if(this.hasResultRule) {
        if(!this.temporaryData?.length){
          this.temporaryData.push(...postData);
          this.isRuleData = Array.from(this.temporaryData);
          this.ruleData = this.isRuleData.map(e => this.setRule(e));
        }else {
          this.temporaryData.push(...postData);
          this.isRuleData.push(...postData);
          this.ruleData.push(...postData.map(e => this.setRule(e)))
        }
        this.reset(false);
        this.isLoading = true;
        await new Promise(resolve => setTimeout(resolve, 1000));
        this.isLoading = false;
        this.$toast.success('Filter Success. Click on Funnel to view the configuration result.');
      }else {
        this.reset(false);
        this.isLoading = true;
        await new Promise(resolve => setTimeout(resolve, 1000));
        this.isLoading = false;
        this.$toast.warning('No Data.');
      };
    },
    /**
     * create map
     */
    sumbitAll() {
      this.$emit('submit-all');
    },
    /**
     * hide map
     */
    hide() {
      // 因 trace api 連動，所以關閉側邊欄時讓數值歸 1
      this.allMapDataStore.traceId = 1;
      this.allMapDataStore.getTraceDetail();
    }
  },
}
</script>

<style scoped>
#searchFiles::-webkit-search-cancel-button{
  appearance: none;
}
</style>
