<template>
  <el-form :model="state.form.warningScopeRows" ref="form_ref" :rules="tableRules" label-width="0" style="width: 100%">
    <el-table :data="state.form.warningScopeRows" stripe border empty-text="请输入表达式，根据表达式$...$自动生成表格">
      <el-table-column
        v-for="header in warningScopeHeaders"
        :prop="header.prop"
        :key="header.prop"
        :label="header.label"
        :width="header.width">
        <template #default="{ $index }">
          <div v-if="header.prop == 'indicator_tag'">
            <el-form-item :prop="`[${$index}].input_indicator_tag`" :rules="tableRules.input_indicator_tag">
              <el-input
                v-model="state.form.warningScopeRows[$index].input_indicator_tag"
                placeholder="请选择指标标签"
                ref="inputRef"
                @blur="blurInput($index)"
                @focus="inputLabel($index, false)"
                @input="inputLabel($index, true)"></el-input>
            </el-form-item>
          </div>
          <div v-else-if="header.prop == 'cname'">
            <el-form-item :prop="`[${$index}].cname`" :rules="tableRules.cname">
              <el-input
                style="flex: 1"
                v-model="state.form.warningScopeRows[$index].cname"
                :maxlength="20"
                show-word-limit
                placeholder="请输入中文名称">
              </el-input>
            </el-form-item>
          </div>
          <div v-else-if="header.prop == 'is_required'">
            <el-form-item :prop="`[${$index}].is_required`" :rules="tableRules.is_required">
              <el-select v-model="state.form.warningScopeRows[$index].is_required" placeholder="请选择" style="flex: 1">
                <el-option v-for="(value, key) in tableSelOptions" :key="key" :label="value" :value="key"> </el-option>
              </el-select>
            </el-form-item>
          </div>
          <div v-else-if="header.prop == 'is_linkage'">
            <el-form-item :prop="`[${$index}].is_linkage`" :rules="tableRules.is_linkage">
              <el-select v-model="state.form.warningScopeRows[$index].is_linkage" placeholder="请选择" style="flex: 1">
                <el-option v-for="(value, key) in tableSelOptions" :key="key" :label="value" :value="key"> </el-option>
              </el-select>
            </el-form-item>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <el-popover
      v-if="inputRef?.length > 0"
      :virtual-ref="inputRef?.[active_index]"
      :visible="visible"
      popper-class="cascader-operation"
      placement="bottom-start">
      <div class="filter-first-tree-lists" @mousedown.prevent="" v-if="active_row">
        <ul class="bg-scroll" ref="first_options_lists" v-show="firstOptions.length > 0">
          <li
            v-for="data in firstOptions"
            :key="data"
            :class="{
              active: active_row.indicator_scope == data.label,
            }">
            <div class="first-label-main" @click="chooseTreeFirst(active_index, data)">
              <div class="tree-label" v-html="data.label_html"></div>
              <div class="tree-icon">
                <bg-icon
                  style="font-size: 15px; color: #404a62"
                  class="is-loading"
                  :class="{ 'loading-show': data.isLoading }"
                  icon="#bg-ic-loading"></bg-icon>
                <bg-icon style="font-size: 13px; color: #404a62" icon="#bg-ic-arrow-right"></bg-icon>
              </div>
            </div>
          </li>
        </ul>
        <ul v-show="firstOptions.length == 0">
          <li class="no-data">
            {{
              active_row.input_indicator_tag
                ? firstOptionsLoading
                  ? "查询中"
                  : "未查询到相关指标范围数据"
                : "请输入查询"
            }}
          </li>
        </ul>
        <ul class="bg-scroll" v-show="lastOptions?.length > 0">
          <li
            v-for="child in lastOptions"
            :key="child"
            @click="chooseTreeLast(child, active_index)"
            :class="{ active: active_row.indicator_tag == child }">
            {{ child }}
          </li>
        </ul>
        <ul v-show="active_row.indicator_scope && lastOptions?.length == 0">
          <li class="no-data">
            {{ lastOptionsLoading ? "查询中" : "未查询到相关指标标签" }}
          </li>
        </ul>
      </div>
    </el-popover>
  </el-form>
</template>

<script setup>
import { reactive, watch, nextTick, computed, ref, onMounted } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";

const props = defineProps({
  indicator_expression: {
    type: String,
    default: "",
  },
  warningScopeRows: {
    type: Array,
    default: () => [],
  },
});
// 是否是必填和是否联动下拉数据
const tableSelOptions = ["否", "是"];
// 表格表头
const warningScopeHeaders = [
  {
    prop: "key",
    label: "变量名称",
    width: 100,
  },
  {
    prop: "indicator_tag",
    label: "指标标签",
  },
  {
    prop: "cname",
    label: "中文名称",
  },
  {
    prop: "is_required",
    label: "是否必填",
    width: 150,
  },
  {
    prop: "is_linkage",
    label: "是否联动",
    width: 150,
  },
];
// 表单数据
const state = reactive({
  form: {
    warningScopeRows: [],
  },
});
// 表单验证
const tableRules = {
  input_indicator_tag: [{ required: true, message: "请输入", trigger: "blur" }],
  cname: [{ required: true, message: "请输入", trigger: "blur" }],
};
// 获取到的第一级指标范围基础数据集合
const dataTreeDefault = ref([]);
// 是否是输入触发
const isInput = ref(false);
const first_options_lists = ref(null);
// 指标输入框元素集合
const inputRef = ref(null);
// 监听父组件传过来的指标表达式
watch(
  () => props.indicator_expression,
  async (n) => {
    await nextTick();
    let tableCreateKeys = n?.match(/\$(.+?)\$/g) || [];
    let arr = [];
    tableCreateKeys.forEach((e) => {
      let i = state.form.warningScopeRows.findIndex((el) => el.key == e);
      if (i >= 0) {
        arr[i] = state.form.warningScopeRows[i];
      } else {
        arr.push({
          key: e,
          input_indicator_tag: "",
          indicator_scope: "",
          indicator_tag: "",
          oldQuery: "",
          cname: "",
          is_required: 1,
          is_linkage: 0,
        });
      }
    });
    state.form.warningScopeRows = arr;
  }
);
// 当前操作input下标
const active_index = ref("");
// 计算：当前操作input所在行数据源
const active_row = computed(() => {
  if (active_index.value === "") return null;
  return state.form.warningScopeRows[active_index.value];
});
// 下拉是否可见
const visible = ref(false);
// 第一层下拉
const firstOptions = ref([]);
// 第一层下拉加载动画
const firstOptionsLoading = ref(false);
// 最后一层下拉
const lastOptions = ref([]);
// 最后一层的下拉加载动画
const lastOptionsLoading = ref(false);
// 计算：根据聚焦的input 获取当前查询的关键词
const query = computed(() => {
  return (index) => {
    const { input_indicator_tag, oldQuery } = state.form.warningScopeRows[index];
    return inputType.value ? input_indicator_tag : oldQuery;
  };
});
// 选择第一级，获取第二级数据
const chooseTreeFirst = (index, data, isInfo = false) => {
  lastOptionsLoading.value = true;
  let i = "";
  // 是否是父组件传过来的默认展示数据
  if (!isInfo) {
    inputRef.value[index].focus();
    i = firstOptions.value.findIndex((e) => e.label == data.label);
    firstOptions.value[i].isLoading = true;
    state.form.warningScopeRows[index].indicator_tag = "";
    state.form.warningScopeRows[index].indicator_scope = data.label;
    lastOptions.value = [];
  }
  const params = {
    label_name: data.label,
  };
  axios
    .get("/v1/api/prometheus", { params })
    .then((res) => {
      if (res.data.code == 200) {
        lastOptions.value = res.data.data?.list || [];
      } else {
        ElMessage.error(res.data.msg);
      }
    })
    .finally(() => {
      lastOptionsLoading.value = false;
      if (i === "") return;
      firstOptions.value[i].isLoading = false;
    });
};
// 获取第一级数据
const getDataTreeLevelFirst = () => {
  axios.get("/v1/api/prometheus").then((res) => {
    if (res.data.code == 200) {
      dataTreeDefault.value =
        res.data.data.list.map((e) => {
          return {
            label: e,
            isLoading: false,
          };
        }) || [];
    } else {
      ElMessage.error(res.data.msg);
    }
  });
  for (let i = 0; i < 1000; i++) {
    dataTreeDefault.value.push({
      label: "total" + i,
      value: "total" + i,
    });
  }
};
let timer = null;
const inputType = ref(false);
const TreeFilter = async (index) => {
  const { input_indicator_tag } = active_row.value;
  // 如果没有输入，或者清空输入，则清除已选中的所有东西和所有下拉数据，并返回
  if (input_indicator_tag == "") {
    lastOptions.value = [];
    state.form.warningScopeRows[index].indicator_scope = "";
    state.form.warningScopeRows[index].indicator_tag = "";
    state.form.warningScopeRows[index].oldQuery = "";
    return;
  }
  let q = query.value(index);
  // 提升性能问题使用for循环遍历
  for (let i = 0; i < dataTreeDefault.value.length; i++) {
    // 不符合直接跳出当次循环
    if (!dataTreeDefault.value[i].label.includes(q)) continue;
    firstOptions.value.push({
      ...dataTreeDefault.value[i],
      // 高亮显示和输入匹配的项
      label_html: dataTreeDefault.value[i].label.replaceAll(q, `<span class='mate-str'>${q}</span>`),
    });
  }
  // 如果第一级下拉没有数据，则隐藏第二级下拉，并清除当前现在的指标范围
  if (firstOptions.value.length == 0) {
    lastOptions.value = [];
    state.form.warningScopeRows[index].indicator_scope = "";
  }
  // 结束查询中
  firstOptionsLoading.value = false;
  // 查询后第一级滚动条滚动到顶部
  first_options_lists.value.scrollTop = 0;
};
// 输入模糊查询数据
const inputLabel = async (index, type) => {
  visible.value = false;
  firstOptions.value = [];
  await nextTick();
  active_index.value = index;
  // 记录当前是聚焦还是输入
  inputType.value = type;
  visible.value = true;
  // 第一级显示查询中
  firstOptionsLoading.value = true;
  // 用户输入节流
  if (timer) {
    clearTimeout(timer);
    timer = null;
  }
  timer = setTimeout(
    () => {
      // 过滤下拉数据
      TreeFilter(index);
    },
    // 如果是聚集input的时候不需要节流，输入节流
    type ? 500 : 0
  );
};
// 失去焦点是隐藏popper
const blurInput = (index) => {
  // 判断是聚焦失去焦点还是输入后失去焦点，输入后失去焦点记录输入的内容，聚焦失去焦点还是使用之前的记录
  state.form.warningScopeRows[index].oldQuery = query.value(index);
  // 隐藏popper
  visible.value = false;
};
// 选择范围中的属性
const chooseTreeLast = (last, index) => {
  state.form.warningScopeRows[index].input_indicator_tag = last;
  state.form.warningScopeRows[index].indicator_tag = last;
  isInput.value = false;
  inputRef.value[index].blur();
};
// form表单元素
const form_ref = ref(null);
// 提交操作调用
const Submit = async () => {
  let form_valid = await new Promise((resolve, reject) => {
    form_ref.value.validate((res) => resolve(res));
  });
  let isFull = true;
  try {
    state.form.warningScopeRows.forEach((e, i) => {
      if (e.indicator_scope == "" || e.indicator_tag == "") {
        throw `第${i + 1}条数据的指标没有选择！`;
      }
    });
  } catch (e) {
    if (e) {
      ElMessage.error(e);
      isFull = false;
    }
  }
  return form_valid && isFull;
};
// 监听编辑的原数据，并显示
watch(
  () => props.warningScopeRows,
  (n) => {
    state.form.warningScopeRows =
      n?.map((e, i) => {
        chooseTreeFirst(i, { label: e.indicator_scope }, true);
        return {
          key: e.key,
          input_indicator_tag: e.indicator_tag,
          indicator_scope: e.indicator_scope,
          indicator_tag: e.indicator_tag,
          oldQuery: e.indicator_scope,
          cname: e.cname,
          is_required: e.is_required,
          is_linkage: e.is_linkage,
        };
      }) || [];
  },
  {
    deep: true,
    immediate: true,
  }
);
// 获取第一级指标范围列表
onMounted(() => {
  getDataTreeLevelFirst();
});
defineExpose({
  Submit,
  form: state.form,
  form_ref,
});
</script>
<style lang="scss" scoped>
.indictor-tag {
  width: 100%;
}
</style>
<style lang="scss">
.cascader-operation {
  width: auto !important;
  padding: 0 !important;
  min-width: 180px !important;
  position: relative;
  min-height: 204px;
  .el-scrollbar {
    border-radius: 0;
  }
  .filter-first-tree-lists {
    height: 240px;
    display: flex;
    min-width: 100%;
    content-visibility: auto;
    contain-intrinsic-size: 34px;
    ul {
      min-width: 180px;
      height: 100%;
      &:not(:first-child) {
        border-left: 1px solid #ddd;
      }
      li {
        padding-left: 20px;
        line-height: 34px;
        // max-width: 400px;
        word-break: break-all;
        transition: all 300ms;
        font-size: 12px;
        &:hover {
          background-color: #f1f1f1;
        }
        cursor: pointer;
        &.active {
          font-weight: bold;
          background-color: #f1f1f1;
        }
      }
    }
    .first-label-main {
      padding-right: 48px;
      position: relative;
      .tree-label {
        width: 100%;
      }
      .tree-icon {
        width: 40px;
        height: 100%;
        position: absolute;
        right: 0;
        top: 0;
        display: flex;
        align-items: center;
        svg {
          width: 20px;
        }
        .is-loading {
          animation: rotate 3s linear infinite;
          opacity: 0;
          &.loading-show {
            opacity: 1;
          }
        }
        @keyframes rotate {
          from {
            transform: rotate(0deg);
          }
          to {
            transform: rotate(360deg);
          }
        }
      }
    }
    .no-data {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      color: gray;
      box-sizing: border-box;
      padding: 0 20px;
    }
  }
}
.mate-str {
  font-weight: bold;
}
</style>
