import { defineStore } from "pinia";
import moment from "moment";
import apiError from '@/module/apiError.js';
import { Decimal } from 'decimal.js';

export default defineStore('allMapDataStore', {
  state: () => ({
    baseLogId: null,
    logId: null,
    traceId: null,
    baseTraceId: 1,
    tempFilterId: null,
    createFilterId: null,
    filterName: null,
    allProcessMap: {},
    allBpmn: {},
    allStats: {},
    allInsights: {},
    allTrace: [],
    allBaseTrace: [],
    allCase: [],
    allBaseCase: [],
    allTraceTaskSeq: [],
    allBaseTraceTaskSeq: [],
    allFilterTask: [],
    allFilterStartToEnd: [],
    allFilterEndToStart: [],
    allFilterTimeframe: {},
    allFilterTrace: [],
    allFilterAttrs: [],
    hasResultRule: null, // click Apply 後檢查是否有 Data
    temporaryData: [], // 沒被 apply all 的 Data
    postRuleData: [], // has-result API & temp-filters API 的 Data
    ruleData: [], // Funnle view's data
    isRuleData: [], // toggle button data
    allFunnelData: [],
    isUpdataFilter: false, // 是否成功儲存 Filter 檔
    selectTimeFrame: [], // user select time start and end
    infinite404: null, // 無限滾動式是否到底要換頁
    infiniteStart: 0, // 無限滾動 case 開始的數字
    baseInfiniteStart: 0, // 無限滾動 case 開始的數字
  }),
  getters: {
    processMap: state => {
      return state.allProcessMap;
    },
    bpmn: state => {
      return state.allBpmn;
    },
    stats: state => {
      return state.allStats;
    },
    insights: state => {
      return state.allInsights;
    },
    traces: state => {
      return state.allTrace.sort((x, y) => x.id - y.id);
    },
    baseTraces: state => {
      return state.allBaseTrace.sort((x, y) => x.id - y.id);
    },
    cases: state => {
      return state.allCase;
    },
    baseCases: state => {
      return state.allBaseCase;
    },
    infiniteFirstCases: state => {
      if(state.infiniteStart === 0) return state.allCase;
    },
    BaseInfiniteFirstCases: state => {
      if(state.BaseInfiniteStart === 0) return state.allBaseCase;
    },
    traceTaskSeq: state => {
      return state.allTraceTaskSeq;
    },
    baseTraceTaskSeq: state => {
      return state.allBaseTraceTaskSeq;
    },
    // All tasks
    filterTasks: state => {
      return state.allFilterTask;
    },
    // form start to end tasks
    filterStartToEnd: state => {
      return state.allFilterStartToEnd;
    },
    // form end to start tasks
    filterEndToStart: state => {
      return state.allFilterEndToStart;
    },
    filterTimeframe: state => {
      return state.allFilterTimeframe;
    },
    filterTrace: state => {
      return state.allFilterTrace;
    },
    filterAttrs: state => {
      if(state.allFilterAttrs !== null){
        state.allFilterAttrs.map(att => {
          switch (att.type) {
            case 'date':
              att.min = att.min !== null ? moment(att.min).format('YYYY/MM/DD HH:mm') : null;
              att.max = att.max !== null ? moment(att.max).format('YYYY/MM/DD HH:mm') : null;
              break;
            case 'float':
              // Decimal.ROUND_UP|0: 無條件進位； Decimal.ROUND_DOWN|1: 無條件捨去。
              att.min = att.min !== null ? Number(new Decimal(att.min).toFixed(2, 1)) : null;
              att.max = att.max !== null ? Number(new Decimal(att.max).toFixed(2, 0)) : null;
              break
            default:
              break;
          }
          return att;
        });
        return state.allFilterAttrs;
      }
    },
    allFunnels: state => {
      return state.allFunnelData;
    },
  },
  actions: {
    /**
     * fetch discover api, include '/process-map, /bpmn, /stats, /insights'.
     */
    async getAllMapData() {
      let logId = this.logId;
      let tempFilterId = this.tempFilterId;
      let createfilterId = this.createFilterId
      let api = '';

      // 先判斷暫存 再判斷 filter 最後 log
      if(tempFilterId != null) api = `/api/temp-filters/${tempFilterId}/discover`;
      else if(createfilterId!= null) api = `/api/filters/${createfilterId}/discover`;
      else api = `/api/logs/${logId}/discover`;

      try {
        const response = await this.$axios.get(api);
        this.allProcessMap = response.data.process_map;
        this.allBpmn = response.data.bpmn;
        this.allStats = response.data.stats;
        this.allInsights = response.data.insights;
      } catch(error) {
        apiError(error, 'Failed to load the Map.');
      };
    },
    /**
     * fetch trace api.
     */
    async getAllTrace() {
      let logId = this.logId;
      let tempFilterId = this.tempFilterId;
      let createfilterId = this.createFilterId;
      let baseLogId = this.baseLogId;
      let baseApi = `/api/logs/${baseLogId}/traces`;
      let api = '';

      // 先判斷暫存 再判斷 filter 最後 log
      if(tempFilterId != null) api = `/api/temp-filters/${tempFilterId}/traces`;
      else if(createfilterId!= null) api = `/api/filters/${createfilterId}/traces`;
      else api = `/api/logs/${logId}/traces`;

      try {
        let baseResponse;
        const response = await this.$axios.get(api);
        this.allTrace = response.data;
        if(baseLogId) baseResponse = await this.$axios.get(baseApi);
        this.allBaseTrace = baseResponse.data;
      } catch(error) {
        apiError(error, 'Failed to load the Trace.');
      }
    },
    /**
     * fetch trace detail api.
     */
    async getTraceDetail() {
      let logId = this.logId;
      let traceId = this.traceId;
      let tempFilterId = this.tempFilterId;
      let createfilterId = this.createFilterId;
      let start = this.infiniteStart;
      let api = '';

      // 先判斷暫存 再判斷 filter 最後 log
      if(tempFilterId != null) api = `/api/temp-filters/${tempFilterId}/traces/${traceId}?start=${start}&page_size=20`;
      else if(createfilterId!= null) api = `/api/filters/${createfilterId}/traces/${traceId}?start=${start}&page_size=20`;
      else api = `/api/logs/${logId}/traces/${traceId}?start=${start}&page_size=20`;

      try {
        const response = await this.$axios.get(api);
        this.allTraceTaskSeq = response.data.task_seq;
        this.allCase = response.data.cases;
        this.allCase.map(c => {
          c.started_at = moment(c.started_at).format('YYYY/MM/DD HH:mm');
          c.completed_at = moment(c.completed_at).format('YYYY/MM/DD HH:mm');
          c.attributes.map(att => {
            switch (att.type) {
              case 'date':
                att.value = att.value !== null ? moment(att.value).format('YYYY/MM/DD HH:mm') : null;
                break;
              case 'float':
                att.value = att.value !== null ? Number(new Decimal(att.value).toFixed(2)) : null;
              default:
                break;
            }
          })
          return this.allCase;
        });
        return this.allCase;
      } catch(error) {
        if(error.response.status === 404) return this.infinite404 = 404;
        apiError(error, 'Failed to load the Trace Detail.');
      };
    },
    /**
     * fetch base log trace detail api.
     */
    async getBaseTraceDetail() {
      let logId = this.baseLogId;
      let traceId = this.baseTraceId;
      let start = this.baseInfiniteStart;
      let api = `/api/logs/${logId}/traces/${traceId}?start=${start}&page_size=20`;

      try {
        const response = await this.$axios.get(api);
        this.allBaseTraceTaskSeq = response.data.task_seq;
        this.allBaseCase = response.data.cases;
        this.allBaseCase.map(c => {
          c.started_at = moment(c.started_at).format('YYYY/MM/DD HH:mm');
          c.completed_at = moment(c.completed_at).format('YYYY/MM/DD HH:mm');
          c.attributes.map(att => {
            switch (att.type) {
              case 'date':
                att.value = att.value !== null ? moment(att.value).format('YYYY/MM/DD HH:mm') : null;
                break;
              case 'float':
                att.value = att.value !== null ? Number(new Decimal(att.value).toFixed(2)) : null;
              default:
                break;
            }
          })
          return this.allBaseCase;
        });
        return this.allBaseCase;
      } catch(error) {
        if(error.response.status === 404) return this.infinite404 = 404;
        apiError(error, 'Failed to load the Base Trace Detail.');
      };
    },
    /**
     * fetch Filter Parameters api.
     */
    async getFilterParams() {
      let logId = this.logId;
      const api = `/api/filters/params?log_id=${logId}`;

      try {
        const response = await this.$axios.get(api);
        this.allFilterTask = response.data.tasks;
        this.allFilterStartToEnd = response.data.sources;
        this.allFilterEndToStart = response.data.sinks;
        this.allFilterTimeframe = response.data.timeframe;
        this.allFilterTrace = response.data.trace;
        this.allFilterAttrs = response.data.attrs;

        let min = this.allFilterTimeframe.x_axis.min;
        let max = this.allFilterTimeframe.x_axis.max;
        // 給 Chart.js 原始資料，格式不同的畫會錯誤輸出
        this.allFilterTimeframe.x_axis.min_base = min;
        this.allFilterTimeframe.x_axis.max_base = max;
        // 轉成無秒的時間格式
        this.allFilterTimeframe.x_axis.min = min !== null ? moment(min).format('YYYY/MM/DD HH:mm') : null;
        this.allFilterTimeframe.x_axis.max = max !== null ? moment(max).format('YYYY/MM/DD HH:mm') : null;
      } catch(error) {
        apiError(error, 'Failed to load the Filter Parameters.');
      };
    },
    /**
     * Test if the Filter Rules Result in Any Data
     */
    async checkHasResult() {
      let logId = this.logId;
      const api = `/api/filters/has-result?log_id=${logId}`;

      try {
        const response = await this.$axios.post(api, this.postRuleData)
        this.hasResultRule = response.data.result;
      } catch(error) {
        apiError(error, 'Failed to load the Has Result.');
      };
    },
    /**
     * Add a New Temporary Filter
     */
    async addTempFilterId() {
      let logId = this.logId;
      const api = `/api/temp-filters?log_id=${logId}`;

      try {
        const response = await this.$axios.post(api, this.postRuleData)
        this.tempFilterId = response.data.id;
      } catch(error) {
        apiError(error, 'Failed to add the Temporary Filters.');
      };
    },
    /**
     * Add a New Filter
     */
    async addFilterId(value) {
      let logId = this.logId;
      const api = `/api/filters?log_id=${logId}`;
      let createFilterObj = {
        name: value,
        rules: this.postRuleData
      };

      try {
        const response = await this.$axios.post(api, createFilterObj);
        this.createFilterId = response.data.id;
        this.tempFilterId = null;
      }catch(error) {
        apiError(error, 'Failed to load the Filters.');
      };
    },
    /**
     * Get Filter Detail
     */
    async fetchFunnel(createfilterId) {
      const api = `/api/filters/${createfilterId}`;

      if(createfilterId){
        try {
          const response = await this.$axios.get(api);
          this.temporaryData = response.data.rules;
          this.logId = response.data.log.id;
          this.filterName = response.data.name;
          this.baseLogId = response.data.log.id;
        }catch(error) {
          apiError(error, 'Failed to get Filter Detail.');
        }
      }
    },
    /**
     * Updata an Existing Filter
     */
    async updataFilter() {
      let createFilterId = this.createFilterId
      const api = `/api/filters/${createFilterId}`;
      const data = this.postRuleData;

      try {
        const response = await this.$axios.put(api, data);
        this.isUpdataFilter = response.status === 200;
      }catch(error) {
        apiError(error, 'Failed to updata an Existing Filter.');
      }
    },
  },
})
