<!--
  ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
  ~ license agreements. See the NOTICE file distributed with
  ~ this work for additional information regarding copyright
  ~ ownership. Apache Software Foundation (ASF) licenses this file to you under
  ~ the Apache License, Version 2.0 (the "License"); you may
  ~ not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied.  See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
-->

<script setup>
  import { reactive, ref, watch } from 'vue';
  import { useRoute } from 'vue-router';
  import { ElMessage } from 'element-plus';
  import { jsonToYaml, yamlToJson } from '@/utils/yaml';
  import { Search, RefreshRight, TrendCharts } from '@element-plus/icons-vue';
  import { getTopNAggregationData } from '@/api/index';
  import CodeMirror from '@/components/CodeMirror/index.vue';
  import FormHeader from '../common/FormHeader.vue';
  import TopNTable from '../common/TopNTable.vue';
  import { Shortcuts, Last15Minutes } from '../common/data';
  import TraceTree from '../TraceTree/TraceContent.vue';

  const route = useRoute();
  const data = reactive({
    group: '',
    name: '',
    type: '',
    operator: '',
    lists: [],
  });
  const yamlRef = ref(null);
  const timeRange = ref([]);
  const yamlCode = ref('');
  const loading = ref(false);
  const showTracesDialog = ref(false);
  const traceData = ref(null);

  // Table columns configuration
  const columns = [
    { label: 'Label', prop: 'label' },
    { label: 'Value', prop: 'value', width: '220' },
  ];

  function initTopNAggregationData() {
    if (!(data.type && data.group && data.name)) {
      return;
    }
    timeRange.value = [new Date(new Date().getTime() - Last15Minutes), new Date()];
    const range = jsonToYaml({
      timeRange: {
        begin: timeRange.value[0],
        end: timeRange.value[1],
      },
    }).data;
    yamlCode.value = `${range}topN: 10
agg: 2
fieldValueSort: 1`;
    fetchTopNAggregationData();
  }

  async function fetchTopNAggregationData(param) {
    loading.value = true;
    const result = await getTopNAggregationData({
      groups: [data.group],
      name: data.name,
      timeRange: { begin: timeRange.value[0], end: timeRange.value[1] },
      topN: 10,
      agg: 2,
      fieldValueSort: 1,
      ...param,
    });
    loading.value = false;
    if (result.error) {
      ElMessage.error({
        message: `Failed to fetch topN aggregation data: ${result.error.message}`,
        type: 'error',
      });
      return;
    }
    traceData.value = result.traces || null;
    data.lists = (result.lists || [])
      .map((d) => d.items.map((item) => ({ label: item.entity[0].value.str.value, value: item.value.int.value })))
      .flat();
  }

  function searchTopNAggregation() {
    yamlRef.value
      .checkYaml(yamlCode.value)
      .then(() => {
        const json = yamlToJson(yamlCode.value).data;
        fetchTopNAggregationData(json);
      })
      .catch((err) => {
        ElMessage({
          dangerouslyUseHTMLString: true,
          showClose: true,
          message: err.message,
          type: 'error',
          duration: 5000,
        });
      });
  }

  function changeTimeRange() {
    const json = yamlToJson(yamlCode.value);
    if (!json.data.timeRange) {
      json.data.timeRange = {
        begin: '',
        end: '',
      };
    }
    json.data.timeRange.begin = timeRange.value[0] ?? null;
    json.data.timeRange.end = timeRange.value[1] ?? null;
    yamlCode.value = jsonToYaml(json.data).data;
  }

  watch(
    () => route,
    () => {
      data.group = route.params.group;
      data.name = route.params.name;
      data.type = route.params.type;
      data.operator = route.params.operator;
      initTopNAggregationData();
    },
    {
      immediate: true,
      deep: true,
    },
  );
</script>

<template>
  <div v-loading="loading">
    <el-card>
      <template #header>
        <FormHeader :fields="data" />
      </template>
      <el-row>
        <el-col :span="10">
          <div class="flex align-item-center" style="height: 40px; width: 100%">
            <el-date-picker
              @change="changeTimeRange"
              v-model="timeRange"
              type="datetimerange"
              :shortcuts="Shortcuts"
              range-separator="to"
              start-placeholder="begin"
              end-placeholder="end"
            />
            <el-button :icon="Search" @click="searchTopNAggregation" style="margin-left: 10px" color="#6E38F7" plain />
          </div>
        </el-col>
        <el-col :span="14">
          <div class="flex align-item-center justify-end" style="height: 30px">
            <el-button :icon="RefreshRight" @click="initTopNAggregationData" plain />
          </div>
        </el-col>
      </el-row>
      <CodeMirror ref="yamlRef" v-model="yamlCode" mode="yaml" style="height: 200px" :lint="true" />
    </el-card>
    <el-card>
      <div style="margin-bottom: 10px; display: flex; justify-content: flex-end">
        <el-button :icon="TrendCharts" @click="showTracesDialog = true" :disabled="!traceData" plain>
          <span>Debug Trace</span>
        </el-button>
      </div>
      <TopNTable
        :data="data.lists"
        :columns="columns"
        :loading="loading"
        :page-size="10"
        :stripe="true"
        :border="true"
        :show-pagination="true"
        empty-text="No data yet"
      />
    </el-card>
  </div>
  <el-dialog
    v-model="showTracesDialog"
    width="90%"
    :destroy-on-close="true"
    @closed="showTracesDialog = false"
    class="trace-dialog"
  >
    <div style="max-height: 74vh; overflow-y: auto">
      <TraceTree :trace="traceData" />
    </div>
  </el-dialog>
</template>

<style lang="scss" scoped>
  :deep(.el-card) {
    margin: 15px;
  }
</style>
