<template>
  <section class="risk-model-section">
    <div class="section-card">
      <div class="section-header">
        <div>
          <div class="section-title">风险模型</div>
          <div class="section-subtitle">展示模型命中统计、筛选条件与关联人员信息</div>
        </div>
      </div>

      <div class="model-workbench">
        <section class="model-list-panel" aria-label="模型预警统计">
          <div class="panel-header">
            <div>
              <div class="panel-title">模型预警统计</div>
              <div class="panel-subtitle">点击筛选</div>
            </div>
          </div>

          <div v-loading="cardLoading" class="model-card-grid">
            <button
              v-for="item in displayCards"
              :key="item.key"
              type="button"
              class="model-card"
              :class="{ 'is-active': isModelSelected(item.key), 'is-external': item.sourceType === 'external' }"
              @click="toggleModelSelection(item.key)"
            >
              <span class="model-card-head">
                <span v-if="item.sourceType === 'external'" class="source-pill is-external">
                  {{ formatSourceLabel(item) }}
                </span>
                <span class="model-card-action">{{ isModelSelected(item.key) ? "已筛选" : "筛选" }}</span>
              </span>
              <span class="model-card-title">{{ item.title }}</span>
              <span class="model-card-metrics">
                <span><strong>{{ item.count }}</strong><em>次</em></span>
                <span><strong>{{ item.peopleCount }}</strong><em>人</em></span>
              </span>
            </button>
          </div>
        </section>

        <section class="model-result-panel" aria-label="命中模型涉及人员">
          <div class="panel-header">
            <div>
              <div class="panel-title">命中模型涉及人员</div>
            </div>
          </div>

          <div class="selected-strip">
            <span class="selected-label">当前筛选</span>
            <div class="selected-content">
              <template v-if="selectedCards.length">
                <el-tag
                  v-for="item in selectedCards"
                  :key="`selected-${item.key}`"
                  size="small"
                  closable
                  effect="plain"
                  @close="toggleModelSelection(item.key)"
                >
                  {{ item.title }}
                </el-tag>
              </template>
              <span v-else class="selected-placeholder">全部模型</span>
            </div>
            <el-button v-if="selectedCards.length" size="mini" type="text" @click="clearSelectedModels">
              清空模型
            </el-button>
          </div>

          <div class="filter-bar">
            <div class="filter-item filter-item--keyword">
              <span class="filter-label">{{ keywordLabel }}</span>
              <el-input
                v-model.trim="keyword"
                size="small"
                clearable
                :placeholder="keywordPlaceholder"
                @keyup.enter.native="handleQuery"
              />
            </div>

            <div v-if="activeSourceType === 'employee'" class="filter-item filter-item--dept">
              <span class="filter-label">部门</span>
              <el-select
                v-model="deptId"
                size="small"
                clearable
                filterable
                :loading="deptLoading"
                placeholder="请选择部门"
              >
                <el-option
                  v-for="item in deptOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </div>

            <div class="filter-item filter-item--mode">
              <span class="filter-label">模型关系</span>
              <el-radio-group
                v-model="matchMode"
                size="small"
                @change="handleMatchModeChange"
              >
                <el-radio-button label="ANY">命中任一模型</el-radio-button>
                <el-radio-button label="ALL">同时命中全部</el-radio-button>
              </el-radio-group>
            </div>

            <div class="filter-actions">
              <el-button size="small" type="primary" @click="handleQuery">查询</el-button>
              <el-button size="small" plain @click="resetQuery">重置</el-button>
            </div>
          </div>

          <el-table v-loading="tableLoading" :data="peopleList" class="model-table">
            <template slot="empty">
              <el-empty :image-size="80" description="当前筛选条件下暂无命中人员" />
            </template>
            <el-table-column type="index" label="序号" width="60" />
            <el-table-column v-if="activeSourceType === 'all'" label="来源" width="84">
              <template slot-scope="scope">
                <el-tag
                  size="mini"
                  effect="plain"
                  :type="scope.row.sourceType === 'external' ? 'success' : ''"
                >
                  {{ scope.row.sourceType === "external" ? "外部" : "员工" }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="name" label="姓名" min-width="100" />
            <el-table-column
              v-if="activeSourceType !== 'external'"
              prop="staffCode"
              :label="activeSourceType === 'all' ? '工号/主体类型' : '工号'"
              min-width="120"
            />
            <el-table-column prop="idNo" label="身份证号" min-width="180" />
            <el-table-column
              prop="department"
              :label="departmentLabel"
              min-width="140"
            />
            <el-table-column label="命中模型" min-width="180">
              <template slot-scope="scope">
                <span>{{ formatModelNames(scope.row.modelNames) }}</span>
              </template>
            </el-table-column>
            <el-table-column label="异常标签" min-width="220">
              <template slot-scope="scope">
                <div v-if="scope.row.hitTagList && scope.row.hitTagList.length" class="hit-tag-list">
                  <el-tag
                    v-for="(tag, index) in scope.row.hitTagList"
                    :key="`${scope.row.staffCode || scope.row.idNo || index}-tag-${index}`"
                    size="mini"
                    effect="plain"
                    :type="resolveModelTagType(tag)"
                  >
                    {{ tag.ruleName }}
                  </el-tag>
                </div>
                <span v-else class="empty-text">-</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="100" align="right">
              <template slot-scope="scope">
                <el-button type="text" size="mini" @click="handleViewProject(scope.row)">{{
                  scope.row.actionLabel || "查看项目"
                }}</el-button>
              </template>
            </el-table-column>
          </el-table>

          <div class="pagination-bar">
            <el-pagination
              background
              layout="prev, pager, next"
              :current-page="pageNum"
              :page-size="pageSize"
              :total="total"
              @current-change="handlePageChange"
            />
          </div>
        </section>
      </div>
    </div>
  </section>
</template>

<script>
import {
  getOverviewExternalRiskModelCards,
  getOverviewExternalRiskModelPeople,
  getOverviewRiskModelPeople,
} from "@/api/ccdi/projectOverview";
import { deptTreeSelect } from "@/api/system/user";

function normalizePeopleRows(rows, sourceType) {
  if (!Array.isArray(rows)) {
    return [];
  }
  return rows.map((item) => ({
    ...item,
    sourceType,
    name: item.staffName || item.name || "",
    staffCode: item.staffCode || "",
    modelNames: Array.isArray(item.modelNames) ? item.modelNames : [],
    hitTagList: Array.isArray(item.hitTagList) ? item.hitTagList : [],
  }));
}

function flattenDeptOptions(nodes, result = []) {
  if (!Array.isArray(nodes)) {
    return result;
  }
  nodes.forEach((item) => {
    const value = item.id || item.deptId;
    const label = item.label || item.deptName;
    if (value !== undefined && label) {
      result.push({ value, label });
    }
    if (Array.isArray(item.children) && item.children.length) {
      flattenDeptOptions(item.children, result);
    }
  });
  return result;
}

export default {
  name: "RiskModelSection",
  props: {
    sectionData: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      selectedModelCodes: [],
      matchMode: "ANY",
      keyword: "",
      deptId: undefined,
      pageNum: 1,
      pageSize: 5,
      cardLoading: false,
      tableLoading: false,
      deptLoading: false,
      deptOptions: [],
      externalCards: [],
      peopleList: [],
      total: 0,
    };
  },
  computed: {
    projectId() {
      return this.sectionData && this.sectionData.projectId;
    },
    cards() {
      if (!Array.isArray(this.sectionData && this.sectionData.cardList)) {
        return [];
      }
      return this.sectionData.cardList
        .filter((item) => !String(item.key || item.modelCode || "").startsWith("EXTERNAL_"))
        .map((item) => ({
          key: item.key || item.modelCode,
          title: item.title || item.modelName,
          count: item.count || item.warningCount || 0,
          peopleCount: item.peopleCount || 0,
          sourceType: "employee",
        }));
    },
    displayCards() {
      return [...this.cards, ...this.externalCards];
    },
    activeSourceType() {
      if (!this.selectedModelCodes.length) {
        return "all";
      }
      const selected = this.displayCards.find((item) => this.selectedModelCodes.includes(item.key));
      return selected && selected.sourceType === "external" ? "external" : "employee";
    },
    keywordLabel() {
      if (this.activeSourceType === "external") {
        return "姓名或证件号";
      }
      if (this.activeSourceType === "all") {
        return "姓名/证件号/工号";
      }
      return "员工姓名或工号";
    },
    keywordPlaceholder() {
      if (this.activeSourceType === "external") {
        return "请输入姓名或证件号";
      }
      if (this.activeSourceType === "all") {
        return "请输入姓名、证件号或工号";
      }
      return "请输入员工姓名或工号";
    },
    departmentLabel() {
      if (this.activeSourceType === "external") {
        return "涉及对象";
      }
      if (this.activeSourceType === "all") {
        return "所属部门/涉及对象";
      }
      return "所属部门";
    },
    selectedModelText() {
      if (!this.selectedModelCodes.length) {
        return "全部模型";
      }
      return this.displayCards
        .filter((item) => this.selectedModelCodes.includes(item.key))
        .map((item) => item.title)
        .join("、");
    },
    selectedCards() {
      return this.displayCards.filter((item) => this.selectedModelCodes.includes(item.key));
    },
  },
  watch: {
    projectId: {
      immediate: true,
      handler() {
        this.selectedModelCodes = [];
        this.$emit("selection-change", this.selectedModelCodes);
        this.pageNum = 1;
        this.loadExternalCards();
        this.fetchPeopleList();
      },
    },
  },
  created() {
    this.loadDeptOptions();
  },
  methods: {
    isModelSelected(modelCode) {
      return this.selectedModelCodes.includes(modelCode);
    },
    formatSourceLabel(item) {
      return item && item.sourceType === "external" ? "外部" : "员工";
    },
    clearSelectedModels() {
      this.selectedModelCodes = [];
      this.$emit("selection-change", this.selectedModelCodes);
      this.pageNum = 1;
      this.fetchPeopleList({ syncCardLoading: true });
    },
    toggleModelSelection(modelCode) {
      const target = this.displayCards.find((item) => item.key === modelCode);
      const targetSourceType = target && target.sourceType === "external" ? "external" : "employee";
      const currentSourceType = this.activeSourceType;
      if (this.selectedModelCodes.length && targetSourceType !== currentSourceType) {
        this.selectedModelCodes = [];
      }
      if (this.selectedModelCodes.includes(modelCode)) {
        this.selectedModelCodes = this.selectedModelCodes.filter((item) => item !== modelCode);
      } else {
        this.selectedModelCodes = [...this.selectedModelCodes, modelCode];
      }
      this.$emit("selection-change", this.selectedModelCodes);
      if (targetSourceType === "external") {
        this.deptId = undefined;
      }
      this.pageNum = 1;
      this.fetchPeopleList({ syncCardLoading: true });
    },
    handleMatchModeChange() {
      this.pageNum = 1;
      this.fetchPeopleList();
    },
    handleQuery() {
      this.pageNum = 1;
      this.fetchPeopleList();
    },
    resetQuery() {
      this.selectedModelCodes = [];
      this.$emit("selection-change", this.selectedModelCodes);
      this.matchMode = "ANY";
      this.keyword = "";
      this.deptId = undefined;
      this.pageNum = 1;
      this.fetchPeopleList();
    },
    handlePageChange(pageNum) {
      this.pageNum = pageNum;
      this.fetchPeopleList();
    },
    buildPeopleParams(sourceType = this.activeSourceType, overrides = {}) {
      return {
        projectId: this.projectId,
        modelCodes: this.selectedModelCodes,
        matchMode: this.matchMode,
        keyword: this.keyword,
        deptId: sourceType === "employee" && this.activeSourceType === "employee" ? this.deptId : undefined,
        pageNum: this.pageNum,
        pageSize: this.pageSize,
        ...overrides,
      };
    },
    formatModelNames(modelNames) {
      if (!Array.isArray(modelNames) || !modelNames.length) {
        return "-";
      }
      return modelNames.join("、");
    },
    handleViewProject(row) {
      if ((row && row.sourceType === "external") || this.activeSourceType === "external") {
        this.$emit("view-external-detail", row);
        return;
      }
      this.$emit("view-project-analysis", row);
    },
    resolveModelTagType(tag) {
      if (!this.selectedModelCodes.length) {
        return "";
      }
      if (this.selectedModelCodes.includes(tag.modelCode)) {
        return "danger";
      }
      return "";
    },
    async loadDeptOptions() {
      this.deptLoading = true;
      try {
        const response = await deptTreeSelect();
        this.deptOptions = flattenDeptOptions(response && response.data);
      } catch (error) {
        this.deptOptions = [];
        console.error("加载部门选项失败", error);
      } finally {
        this.deptLoading = false;
      }
    },
    async loadExternalCards() {
      if (!this.projectId) {
        this.externalCards = [];
        return;
      }
      try {
        const response = await getOverviewExternalRiskModelCards(this.projectId);
        const rows = Array.isArray(response && response.data && response.data.cardList)
          ? response.data.cardList
          : [];
        this.externalCards = rows.map((item) => ({
          key: item.modelCode,
          title: item.modelName,
          count: item.warningCount || 0,
          peopleCount: item.peopleCount || 0,
          sourceType: "external",
        }));
      } catch (error) {
        this.externalCards = [];
        console.error("加载外部人员风险模型失败", error);
      }
    },
    async fetchPeopleList(options = {}) {
      if (!this.projectId) {
        this.peopleList = [];
        this.total = 0;
        return;
      }

      const { syncCardLoading = false } = options;
      if (syncCardLoading) {
        this.cardLoading = true;
      }
      this.tableLoading = true;
      try {
        if (this.activeSourceType === "all") {
          await this.fetchAllPeopleList();
          return;
        }
        const requestFn = this.activeSourceType === "external"
          ? getOverviewExternalRiskModelPeople
          : getOverviewRiskModelPeople;
        const response = await requestFn(this.buildPeopleParams());
        const data = (response && response.data) || {};
        this.peopleList = normalizePeopleRows(
          data.rows,
          this.activeSourceType === "external" ? "external" : "employee"
        );
        this.total = Number(data.total || 0);
      } catch (error) {
        this.peopleList = [];
        this.total = 0;
        console.error("加载风险模型命中人员失败", error);
      } finally {
        this.tableLoading = false;
        if (syncCardLoading) {
          this.cardLoading = false;
        }
      }
    },
    async fetchAllPeopleList() {
      const countParams = {
        modelCodes: [],
        pageNum: 1,
        pageSize: 1,
      };
      const [employeeCountRes, externalCountRes] = await Promise.all([
        getOverviewRiskModelPeople(this.buildPeopleParams("employee", countParams)),
        getOverviewExternalRiskModelPeople(this.buildPeopleParams("external", countParams)),
      ]);
      const employeeTotal = Number((employeeCountRes && employeeCountRes.data && employeeCountRes.data.total) || 0);
      const externalTotal = Number((externalCountRes && externalCountRes.data && externalCountRes.data.total) || 0);
      const offset = (this.pageNum - 1) * this.pageSize;
      const rows = [];

      if (offset < employeeTotal) {
        const employeeLimit = offset + this.pageSize;
        const employeeRes = await getOverviewRiskModelPeople(this.buildPeopleParams("employee", {
          modelCodes: [],
          pageNum: 1,
          pageSize: employeeLimit,
        }));
        const employeeRows = normalizePeopleRows(
          employeeRes && employeeRes.data && employeeRes.data.rows,
          "employee"
        );
        rows.push(...employeeRows.slice(offset, offset + this.pageSize));
      }

      if (rows.length < this.pageSize) {
        const externalOffset = Math.max(0, offset - employeeTotal);
        if (externalOffset < externalTotal) {
          const externalLimit = externalOffset + (this.pageSize - rows.length);
          const externalRes = await getOverviewExternalRiskModelPeople(this.buildPeopleParams("external", {
            modelCodes: [],
            pageNum: 1,
            pageSize: externalLimit,
          }));
          const externalRows = normalizePeopleRows(
            externalRes && externalRes.data && externalRes.data.rows,
            "external"
          );
          rows.push(...externalRows.slice(externalOffset, externalOffset + (this.pageSize - rows.length)));
        }
      }

      this.peopleList = rows;
      this.total = employeeTotal + externalTotal;
    },
  },
};
</script>

<style lang="scss" scoped>
.risk-model-section {
  margin-bottom: 16px;
}

.section-card {
  padding: 18px;
  border-radius: 8px;
  background: #fff;
  border: 1px solid var(--ccdi-border);
  box-shadow: var(--ccdi-shadow);
}

.section-header {
  margin-bottom: 18px;
  padding-left: 12px;
  border-left: 4px solid var(--ccdi-primary);
}

.section-title {
  font-size: 20px;
  line-height: 28px;
  font-weight: 700;
  color: var(--ccdi-text-primary);
}

.section-subtitle {
  margin-top: 6px;
  font-size: 12px;
  color: var(--ccdi-text-muted);
}

.model-workbench {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.model-list-panel,
.model-result-panel {
  border: 0;
  border-radius: 0;
  background: transparent;
  overflow: hidden;
}

.model-result-panel {
  min-width: 0;
  padding-bottom: 12px;
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 38px;
  padding: 0 2px 10px;
}

.panel-title {
  font-size: 15px;
  line-height: 20px;
  font-weight: 700;
  color: var(--ccdi-text-primary);
}

.panel-subtitle {
  margin-top: 2px;
  font-size: 12px;
  color: var(--ccdi-text-muted);
}

.model-card-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  padding: 0;
}

.model-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 104px;
  width: 100%;
  padding: 12px;
  border: 1px solid #e4edf6;
  border-radius: 6px;
  background: #fff;
  color: var(--ccdi-text-primary);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease;
}

.model-card:hover,
.model-card.is-active {
  border-color: #bdd0e2;
  background: #f3f8fd;
}

.model-card.is-active {
  box-shadow: inset 0 3px 0 var(--ccdi-primary);
}

.model-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.source-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: #edf2f7;
  color: #52677d;
  font-size: 12px;
  flex-shrink: 0;
}

.source-pill.is-external {
  background: #edf7ff;
  color: #2f5f91;
}

.model-card-title {
  display: block;
  margin-top: 12px;
  color: var(--ccdi-text-primary);
  font-size: 13px;
  font-weight: 600;
  line-height: 18px;
}

.model-card-metrics {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}

.model-card-metrics span {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  color: var(--ccdi-text-muted);
}

.model-card-metrics strong {
  color: var(--ccdi-primary);
  font-size: 22px;
  line-height: 1;
}

.model-card-metrics em {
  color: var(--ccdi-text-muted);
  font-size: 12px;
  font-style: normal;
}

.model-card-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 22px;
  min-width: 44px;
  padding: 0 8px;
  border-radius: 4px;
  color: var(--ccdi-primary);
  font-size: 12px;
  background: #eef6ff;
}

.model-card:not(.is-active) .model-card-action {
  background: transparent;
}

.model-card.is-active .model-card-action {
  font-weight: 600;
}

.selected-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 0;
  padding: 0 0 10px;
  border-bottom: 1px solid #edf2f7;
  background: transparent;
}

.selected-label {
  color: var(--ccdi-text-secondary);
  font-size: 14px;
  line-height: 22px;
  flex-shrink: 0;
}

.selected-content {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
  flex: 1;
}

.selected-placeholder {
  color: var(--ccdi-text-muted);
  font-size: 14px;
}

.filter-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 18px;
  margin: 12px 0 14px;
  padding: 0;
  border: 0;
  background: transparent;
}

.filter-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.filter-item--mode {
  flex-wrap: wrap;
}

.filter-item--keyword,
.filter-item--dept {
  min-width: 220px;
}

.filter-item--keyword :deep(.el-input),
.filter-item--dept :deep(.el-select) {
  width: 200px;
}

.filter-label,
.summary-label {
  font-size: 14px;
  line-height: 32px;
  color: var(--ccdi-text-secondary);
  flex-shrink: 0;
  white-space: nowrap;
}

.filter-actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

.model-table {
  margin: 0;
  width: 100%;
  border: 1px solid #e7eef5;
  border-radius: 6px;
  overflow: hidden;
}

:deep(.model-table th) {
  background: #f7fafd;
  color: var(--ccdi-text-secondary);
}

.hit-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.empty-text {
  color: var(--ccdi-text-muted);
}

.pagination-bar {
  display: flex;
  justify-content: flex-end;
  margin: 12px 14px 0;
}

@media (max-width: 1200px) {
  .model-card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 768px) {
  .model-card-grid {
    grid-template-columns: 1fr;
  }

  .filter-item--keyword,
  .filter-item--dept,
  .filter-item--keyword :deep(.el-input),
  .filter-item--dept :deep(.el-select) {
    width: 100%;
  }

  .filter-actions {
    width: 100%;
    justify-content: flex-end;
  }
}
</style>
