<template>
  <div class="label-view">
    <div class="title">全部标注</div>
    <div class="label-list mt20">
      <div v-if="loading" class="empty-text pt20">加载中...</div>
      <div v-else-if="labelList.length === 0" class="empty-text pt20">暂无标注</div>
      <div v-else class="label-item" v-for="item in labelList" :key="item.id">
        <div class="name">
          <span> {{ item.keyword }}</span>
          <el-button v-if="!readonly" class="btn" link @click="delAnnoAction(item)">删除</el-button>
        </div>
        <div class="tags">
          <el-tag
            v-for="tag in sortTagList(item.tagDetailList)"
            :key="tag.id"
            size="large"
            type="warning"
            :class="{ large: isGeneralWord(tag) }"
            :closable="!readonly"
            @close="delTagAction(item, tag)"
          >
            {{ tag.tagName }}
            <template v-if="isGeneralWord(tag)">
              <div class="genaral mt20">
                <span class="mr10">{{ isStandWord(tag.tagName) ? "上位词" : "标准词" }}</span>
                <div v-if="readonly" class="word">
                  {{ item[isStandWord(tag.tagName) ? "parentStandardWordName" : "synonymWordName"] || "--" }}
                </div>
                <el-cascader
                  v-else
                  :model-value="getWordId(item, tag)"
                  :options="isStandWord(tag.tagName) ? fourWortTreeList : wordTreeList"
                  :props="{ label: 'name', value: 'id', emitPath: false, checkStrictly: true }"
                  :show-all-levels="false"
                  clearable
                  filterable
                  @change="selectWordChange($event, item, tag)"
                />
              </div>
              <div
                class="mt5"
                v-if="
                  isStandWord(tag.tagName) &&
                  getWordId(item, tag) &&
                  getWordId(item, tag) !==
                    getHistoryPatentWordId(
                      item.keyword,
                      wordTreeList.filter(it => it.id === item.maxId)
                    )
                "
              >
                <el-text type="warning">
                  <el-icon :size="16"><WarningFilled /></el-icon>
                  与历史标注不符，无法保存词语关系
                </el-text>
              </div>
            </template>
          </el-tag>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, defineProps, defineEmits, computed } from "vue";
import { CascaderValue } from "element-plus";
import { WarningFilled } from "@element-plus/icons-vue";
import { DataAnno, Common } from "@/api/interface/index";
import { getWordTreeList } from "@/api/modules/common";
import {
  saveParentStandard,
  saveSynonymWord,
  deSynonymWord,
  delParentStandardWord,
  delAnno,
  delAnnoTag
} from "@/api/modules/annotation/labeling";
import { GeneralClause } from "@/enums";
// props
interface Props {
  loading: boolean;
  readonly: boolean;
  labelList: DataAnno.LabelList[];
}
type WordTree = Common.ResTreeOptions & { disabled?: boolean; enableFlag?: boolean };

withDefaults(defineProps<Props>(), { readonly: () => true, labelList: () => [] });

// 上位词只显示到5级词，包含词表名共6级
const fourWortTreeList = computed(() => {
  // 过滤到指定深度的递归函数
  function filterTreeByDepth(tree: WordTree[], maxDepth: number, currentDepth = 1) {
    const filteredTree: any = [];
    for (const node of tree) {
      const newNode = { ...node }; // 复制节点，以免修改原始数据
      delete newNode.children; // 删除children
      if (node.children && node.children.length > 0 && currentDepth < maxDepth) {
        newNode.children = filterTreeByDepth(node.children, maxDepth, currentDepth + 1);
      }
      filteredTree.push(newNode);
    }

    return filteredTree;
  }
  return filterTreeByDepth(wordTreeList.value, 6);
});
// emit
const emit = defineEmits(["refreshLabel"]);

// ref
const wordTreeList = ref<WordTree[]>([]);

// function
// 加载标准词列表
async function loadWordList() {
  const res = await getWordTreeList();
  // 设置禁用节点，1.一级词表不可选 2.如果一级词表enableFlag = false则递归子级全部不可选
  function setTreeDisabled(treeList: WordTree[]) {
    for (const item of treeList) {
      item.disabled = true;
      if (item.children) {
        setTreeDisabled(item.children);
      }
    }
  }
  const data: WordTree[] = res.data;
  data.forEach(item => {
    // 1.一级词表不可选
    item.disabled = true;
    if (!item.enableFlag && item.children) {
      // 2.如果一级词表enableFlag = false则递归子级全部不可选
      setTreeDisabled(item.children);
    }
  });
  wordTreeList.value = data;
}
loadWordList();
// 判断是不是 标准词或者同义词
function isGeneralWord(tag: DataAnno.TagItem) {
  return [GeneralClause.STANDARD, GeneralClause.SYNONYMS].includes(tag.tagName as GeneralClause);
}

// 判断是不是 标准词
function isStandWord(name: string) {
  return name === GeneralClause.STANDARD;
}

// 排序 标准词和同义词放到结尾
function sortTagList(tagDetailList: DataAnno.TagItem[]) {
  const result = [...(tagDetailList || [])];
  const standIndex = result.findIndex(item => item.tagName === GeneralClause.STANDARD);
  const synonIndex = result.findIndex(item => item.tagName === GeneralClause.SYNONYMS);
  let standItem: DataAnno.TagItem | null = null;
  let synonItem: DataAnno.TagItem | null = null;
  if (standIndex > -1) {
    standItem = result.splice(standIndex, 1)[0];
  }
  if (synonIndex > -1) {
    synonItem = result.splice(synonIndex, 1)[0];
  }
  standItem && result.push(standItem);
  synonItem && result.push(synonItem);
  return result;
}

// 选择标准词或者同义词
async function selectWordChange(val: CascaderValue, item: DataAnno.LabelList, tag: DataAnno.TagItem) {
  const isStand = isStandWord(tag.tagName);
  if (val) {
    //  保存
    if (isStand) {
      await saveParentStandard({
        id: item.id,
        parentStandardWordId: val as number
      });
      // 标准词可能会新增词语关系，所以需要重新加载
      loadWordList();
    } else {
      await saveSynonymWord({
        id: item.id,
        synonymWordId: val as number
      });
    }
  } else {
    // 移除
    if (isStand) {
      await delParentStandardWord({
        id: item.id
      });
    } else {
      await deSynonymWord({
        id: item.id
      });
    }
  }
  emit("refreshLabel");
}

// 移除标注
async function delAnnoAction(item: DataAnno.LabelList) {
  await delAnno({ id: item.id });
  emit("refreshLabel");
}

// 移除标注标签
async function delTagAction(item: DataAnno.LabelList, tag: DataAnno.TagItem) {
  await delAnnoTag({ id: item.id, tagId: tag.id });
  emit("refreshLabel");
}

// 获取词语id
function getWordId(item: DataAnno.LabelList, tag: DataAnno.TagItem) {
  return (isStandWord(tag.tagName) ? item.parentStandardWordId : item.synonymWordId) as number;
}
// 递归获取历史标注标准词的上位词ID
function getHistoryPatentWordId(wordName: string, treeList: Common.ResTreeOptions[]): number {
  for (const item of treeList) {
    if (item.parentId > 0 && item.name === wordName) return item.parentId;
    if (item.children) {
      const result = getHistoryPatentWordId(wordName, item.children);
      if (result > 0) return result;
    }
  }
  return 0;
}
</script>

<style lang="scss" scoped>
.label-view {
  padding: 30px 20px;
  .title {
    font-size: 24px;
    font-weight: bold;
    line-height: 36px;
    color: #333333;
    text-align: center;
  }
  .label-list {
    .empty-text {
      font-size: 16px;
      color: #999999;
      text-align: center;
    }
    .label-item {
      .name {
        display: flex;
        align-items: center;
        justify-content: space-between;
        height: 36px;
        padding: 8px 20px 8px 10px;
        font-size: 16px;
        line-height: 20px;
        color: #333333;
        background: #f5f7fa;
        border-radius: 1px;
        .btn {
          font-size: 12px;
          color: #999999;
        }
      }
      .tags {
        padding: 20px 0;
        .el-tag {
          margin-right: 20px;
          margin-bottom: 20px;
          background: #fff8f2;
          border: 1px solid #ba7d45;
          border-radius: 4px;
          :deep(.el-tag__content) {
            font-size: 16px;
            color: #ba7d45;
          }
          &.large {
            position: relative;
            display: block;
            width: 100%;
            max-width: 307px;
            height: auto;
            padding: 20px 10px;
            :deep(.el-tag__close) {
              position: absolute;
              top: 10px;
              right: 10px;
            }
          }
          .genaral {
            display: flex;
            align-items: center;
            > span {
              font-size: 16px;
              color: #333333;
            }
            .word {
              width: 100%;
              height: 32px;
              padding: 0 10px;
              font-size: 16px;
              line-height: 32px;
              color: #333333;
              background: #ffffff;
              border-radius: 4px 4px 0 0;
            }
            :deep(.el-cascader) {
              flex: 1;
              margin-right: 10px;
              .el-input__wrapper {
                box-shadow: none;
              }
              .el-input__inner {
                height: 32px;
              }
            }
          }
        }
      }
    }
  }
}
</style>
