<template>
  <el-dialog
    title="外部人员详情"
    :visible.sync="visibleProxy"
    width="88%"
    top="2vh"
    append-to-body
    custom-class="project-analysis-dialog external-person-analysis-dialog"
    @close="handleClosed"
  >
    <div class="project-analysis-dialog__body external-analysis-dialog__body">
      <div class="project-analysis-header">
        <div class="project-analysis-header__main">
          <div class="project-analysis-header__title-group">
            <div class="project-analysis-header__title">外部人员详情</div>
          </div>
          <button class="project-analysis-header__close" type="button" aria-label="关闭" @click="closeDialog">
            <i class="el-icon-close" />
          </button>
        </div>
      </div>

      <div
        class="project-analysis-workspace"
        :class="{ 'project-analysis-workspace--sidebar-collapsed': sidebarCollapsed }"
      >
        <div class="project-analysis-layout__sidebar">
          <project-analysis-sidebar
            :sidebar-data="sidebarData"
            :field-labels="sidebarFieldLabels"
            collapsible
            :collapsed="sidebarCollapsed"
            @toggle="toggleSidebar"
          />
        </div>

        <div class="project-analysis-layout__main">
          <el-alert
            v-if="detailError"
            :closable="false"
            class="external-detail-alert"
            type="error"
            show-icon
            :title="detailError"
          />
          <el-tabs v-model="activeTab" class="project-analysis-tabs" stretch @tab-click="handleTabChange">
            <el-tab-pane label="异常明细" name="abnormalDetail">
              <div v-if="detailLoading" v-loading="detailLoading" class="external-detail-loading" />
              <div v-else>
                <project-analysis-abnormal-tab
                  :detail-data="abnormalDetailData"
                  :person="normalizedPerson"
                  :project-id="projectId"
                  :can-operate="canOperate"
                  @evidence-confirm="$emit('evidence-confirm', $event)"
                  @risk-excluded="handleRiskExcluded"
                />
              </div>
            </el-tab-pane>

            <el-tab-pane label="资金流向" name="fund">
              <project-analysis-fund-flow-tab
                v-if="activeTab === 'fund'"
                ref="fundFlowTab"
                :project-id="projectId"
                :person="normalizedPerson"
                :model-summary="fundModelSummary"
              />
            </el-tab-pane>
          </el-tabs>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import { listBankStatement } from "@/api/ccdiProjectBankStatement";
import ProjectAnalysisAbnormalTab from "./ProjectAnalysisAbnormalTab";
import ProjectAnalysisFundFlowTab from "./ProjectAnalysisFundFlowTab";
import ProjectAnalysisSidebar from "./ProjectAnalysisSidebar";

export default {
  name: "ExternalPersonDetailDialog",
  components: {
    ProjectAnalysisAbnormalTab,
    ProjectAnalysisFundFlowTab,
    ProjectAnalysisSidebar,
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    person: {
      type: Object,
      default: () => ({}),
    },
    projectId: {
      type: [String, Number],
      default: null,
    },
    projectName: {
      type: String,
      default: "",
    },
    canOperate: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      activeTab: "abnormalDetail",
      sidebarCollapsed: false,
      detailLoading: false,
      detailError: "",
      statementRows: [],
    };
  },
  computed: {
    visibleProxy: {
      get() {
        return this.visible;
      },
      set(value) {
        this.$emit("update:visible", value);
      },
    },
    displayName() {
      return (this.person && (this.person.name || this.person.staffName)) || "外部人员";
    },
    displayCertNo() {
      return (this.person && (this.person.idNo || this.person.staffIdCard)) || "-";
    },
    displaySubjectType() {
      return (this.person && (this.person.subjectType || this.person.staffCode)) || "外部人员";
    },
    relatedObject() {
      return (this.person && (this.person.relatedObject || this.person.department)) || "-";
    },
    normalizedPerson() {
      return {
        ...(this.person || {}),
        name: this.displayName,
        staffName: this.displayName,
        idNo: this.displayCertNo,
        staffIdCard: this.displayCertNo,
        staffCode: this.displaySubjectType,
        department: this.relatedObject,
      };
    },
    riskTags() {
      if (Array.isArray(this.person && this.person.riskPointTagList)) {
        return this.person.riskPointTagList;
      }
      if (Array.isArray(this.person && this.person.hitTagList)) {
        return this.person.hitTagList;
      }
      return [];
    },
    statementTagKeys() {
      const keys = new Set();
      this.statementRows.forEach((row) => {
        if (!Array.isArray(row && row.hitTags)) {
          return;
        }
        row.hitTags.forEach((tag) => {
          this.buildTagKeys(tag).forEach((key) => keys.add(key));
        });
      });
      return keys;
    },
    sidebarFieldLabels() {
      return {
        staffCode: "主体类型",
        department: "证件号",
        projectName: "所属项目",
      };
    },
    sidebarData() {
      return {
        basicInfo: {
          name: this.displayName,
          riskLevel: (this.person && this.person.riskLevel) || "-",
          staffCode: this.displaySubjectType,
          department: this.displayCertNo,
          projectName: this.projectName || "-",
        },
        modelSummary: {
          modelCount: (this.person && this.person.modelCount) || 0,
          riskTags: this.riskTags,
        },
      };
    },
    abnormalDetailData() {
      const statementGroup = this.buildStatementGroup();
      const objectRecords = this.riskTags
        .filter((tag) => !this.hasMatchedStatementTag(tag))
        .map((tag, index) => this.buildObjectAbnormalRecord(tag, index));
      const groups = [];
      if (statementGroup.records.length) {
        groups.push(statementGroup);
      }
      if (objectRecords.length) {
        groups.push({
          groupCode: "EXTERNAL_OBJECT_WARNING",
          groupName: "对象异常明细",
          groupType: "OBJECT",
          records: objectRecords,
        });
      }
      return {
        groups,
      };
    },
    fundModelSummary() {
      return {
        staffIdCard: this.displayCertNo,
        modelCount: (this.person && this.person.modelCount) || this.riskTags.length,
        riskTags: this.riskTags,
      };
    },
  },
  watch: {
    visible(value) {
      if (value) {
        this.activeTab = "abnormalDetail";
        this.sidebarCollapsed = false;
        this.loadStatementRows();
      }
    },
  },
  methods: {
    async loadStatementRows() {
      if (!this.projectId || !this.displayCertNo || this.displayCertNo === "-") {
        this.statementRows = [];
        return;
      }
      this.statementRows = [];
      this.detailLoading = true;
      this.detailError = "";
      try {
        const response = await listBankStatement({
          projectId: this.projectId,
          ourCertNos: [this.displayCertNo],
          pageNum: 1,
          pageSize: 200,
        });
        this.statementRows = Array.isArray(response && response.rows) ? response.rows : [];
      } catch (error) {
        this.statementRows = [];
        this.detailError = "外部人员流水异常明细加载失败，请稍后重试";
        console.error("加载外部人员流水异常明细失败", error);
      } finally {
        this.detailLoading = false;
      }
    },
    buildStatementGroup() {
      const records = this.statementRows
        .map((row) => this.normalizeStatementRow(row))
        .filter((row) => row.hitTags.length);
      return {
        groupCode: "EXTERNAL_BANK_STATEMENT",
        groupName: "流水异常明细",
        groupType: "BANK_STATEMENT",
        records,
      };
    },
    normalizeStatementRow(row) {
      const hitTags = Array.isArray(row && row.hitTags)
        ? row.hitTags.filter((tag) => this.isMatchedRiskTag(tag))
            .map((tag) => this.enrichStatementTag(tag))
        : [];
      return {
        ...row,
        hitTags,
      };
    },
    isMatchedRiskTag(statementTag) {
      const statementKeys = this.buildTagKeys(statementTag);
      return this.riskTags.some((riskTag) => {
        const riskKeys = this.buildTagKeys(riskTag);
        return statementKeys.some((key) => riskKeys.includes(key));
      });
    },
    hasMatchedStatementTag(riskTag) {
      const riskKeys = this.buildTagKeys(riskTag);
      return riskKeys.some((key) => this.statementTagKeys.has(key));
    },
    buildTagKeys(tag) {
      if (!tag) {
        return [];
      }
      if (typeof tag === "string") {
        return [`name:${tag}`];
      }
      return [
        tag.ruleCode ? `code:${tag.ruleCode}` : "",
        tag.ruleName ? `name:${tag.ruleName}` : "",
      ].filter(Boolean);
    },
    enrichStatementTag(tag) {
      const matched = this.riskTags.find((item) => item && (
        (tag.ruleCode && item.ruleCode === tag.ruleCode)
        || (tag.ruleName && item.ruleName === tag.ruleName)
      ));
      return {
        ...tag,
        modelCode: tag.modelCode || (matched && matched.modelCode),
        modelName: tag.modelName || (matched && matched.modelName),
        reasonDetail: tag.reasonDetail || (matched && matched.reasonDetail),
      };
    },
    buildObjectAbnormalRecord(tag, index) {
      const safeTag = typeof tag === "object" && tag ? tag : {};
      const modelName = safeTag.modelName || "外部人员模型";
      const ruleName = safeTag.ruleName || this.formatRiskTag(tag) || "外部人员预警";
      const matchedRows = this.findMatchedStatementRows(safeTag);
      const statementReason = this.buildStatementReasonDetail(ruleName, matchedRows);
      return {
        modelCode: safeTag.modelCode || `EXTERNAL_MODEL_${index}`,
        ruleCode: safeTag.ruleCode || "",
        title: ruleName,
        subtitle: modelName,
        riskTags: [modelName, this.formatRiskLevel(safeTag.riskLevel)].filter(Boolean),
        reasonDetail: safeTag.reasonDetail || statementReason || this.buildReasonDetail(ruleName, modelName),
        summary: ruleName,
        extraFields: this.buildObjectExtraFields(matchedRows),
      };
    },
    findMatchedStatementRows(riskTag) {
      const riskKeys = this.buildTagKeys(riskTag);
      if (!riskKeys.length) {
        return [];
      }
      return this.statementRows.filter((row) => {
        const hitTags = Array.isArray(row && row.hitTags) ? row.hitTags : [];
        return hitTags.some((tag) => this.buildTagKeys(tag).some((key) => riskKeys.includes(key)));
      });
    },
    buildStatementReasonDetail(ruleName, rows) {
      if (!Array.isArray(rows) || !rows.length) {
        return "";
      }
      const amounts = rows.map((row) => Math.abs(Number(row && row.displayAmount) || 0));
      const totalAmount = amounts.reduce((sum, amount) => sum + amount, 0);
      const maxAmount = amounts.reduce((max, amount) => Math.max(max, amount), 0);
      const latestTime = rows
        .map((row) => row && row.trxDate)
        .filter(Boolean)
        .sort()
        .pop();
      const counterparties = this.collectCounterparties(rows);
      const parts = [
        `命中${ruleName}`,
        `关联流水${rows.length}笔`,
        `累计交易金额${this.formatAmount(totalAmount)}元`,
        `单笔最大金额${this.formatAmount(maxAmount)}元`,
        latestTime ? `最近交易时间${latestTime}` : "",
        counterparties ? `主要对手方：${counterparties}` : "",
      ].filter(Boolean);
      return parts.join("，");
    },
    buildObjectExtraFields(rows) {
      if (!Array.isArray(rows) || !rows.length) {
        return [];
      }
      const amounts = rows.map((row) => Math.abs(Number(row && row.displayAmount) || 0));
      const totalAmount = amounts.reduce((sum, amount) => sum + amount, 0);
      const maxAmount = amounts.reduce((max, amount) => Math.max(max, amount), 0);
      const latestTime = rows
        .map((row) => row && row.trxDate)
        .filter(Boolean)
        .sort()
        .pop();
      return [
        { label: "关联流水", value: `${rows.length}笔` },
        { label: "累计金额", value: `${this.formatAmount(totalAmount)}元` },
        { label: "最大金额", value: `${this.formatAmount(maxAmount)}元` },
        latestTime ? { label: "最近交易", value: latestTime } : null,
        { label: "主要对手方", value: this.collectCounterparties(rows) || "-" },
      ].filter(Boolean);
    },
    collectCounterparties(rows) {
      const names = [];
      rows.forEach((row) => {
        const value = row && (row.customerAccountName || row.customerAccountNo);
        if (value && !names.includes(value)) {
          names.push(value);
        }
      });
      return names.slice(0, 3).join("、");
    },
    formatAmount(value) {
      return (Number(value) || 0).toFixed(2);
    },
    buildReasonDetail(ruleName, modelName) {
      const parts = [
        this.displayName,
        `命中${modelName}`,
        ruleName,
      ].filter(Boolean);
      return parts.join("，");
    },
    formatRiskLevel(value) {
      if (value === "HIGH") {
        return "高风险";
      }
      if (value === "MEDIUM") {
        return "中风险";
      }
      if (value === "LOW") {
        return "低风险";
      }
      return "";
    },
    formatRiskTag(tag) {
      if (typeof tag === "string") {
        return tag;
      }
      if (tag && typeof tag === "object") {
        return tag.ruleName || tag.modelName || tag.label || tag.name || "";
      }
      return "";
    },
    async handleRiskExcluded(payload) {
      await this.loadStatementRows();
      this.$emit("risk-excluded", payload);
    },
    closeDialog() {
      this.visibleProxy = false;
    },
    toggleSidebar() {
      this.sidebarCollapsed = !this.sidebarCollapsed;
      this.$nextTick(() => {
        const fundFlowTab = this.$refs.fundFlowTab;
        if (fundFlowTab && fundFlowTab.ensureGraphReady) {
          fundFlowTab.ensureGraphReady();
        }
      });
    },
    handleClosed() {
      this.activeTab = "abnormalDetail";
      this.sidebarCollapsed = false;
      this.detailLoading = false;
      this.detailError = "";
      this.statementRows = [];
    },
    handleTabChange() {
      this.$nextTick(() => {
        const fundFlowTab = this.$refs.fundFlowTab;
        if (fundFlowTab && fundFlowTab.ensureGraphReady) {
          fundFlowTab.ensureGraphReady();
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.project-analysis-dialog__body {
  display: flex;
  flex-direction: column;
  min-height: calc(92vh - 64px);
  border: 1px solid #dde3ec;
  background: #ffffff;
  overflow: hidden;
}

.project-analysis-header {
  padding: 14px 24px;
  border-bottom: 1px solid #dde3ec;
  background: #ffffff;
}

.project-analysis-header__main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.project-analysis-header__title-group {
  min-width: 0;
}

.project-analysis-header__title {
  color: #101a2b;
  font-size: 20px;
  font-weight: 700;
  line-height: 28px;
}

.project-analysis-header__close {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 2px;
  background: transparent;
  color: #8d99aa;
  font-size: 18px;
  line-height: 34px;
  text-align: center;
  cursor: pointer;
}

.project-analysis-header__close:hover {
  background: #f2f5f8;
  color: #245b8f;
}

.project-analysis-workspace {
  display: flex;
  align-items: flex-start;
  gap: 0;
  min-height: 640px;
  max-height: calc(92vh - 96px);
  padding: 20px 28px 28px;
  overflow: auto;
  background: #ffffff;
}

.project-analysis-workspace--sidebar-collapsed {
  gap: 0;
}

.project-analysis-layout__sidebar {
  position: sticky;
  top: 0;
  flex: 0 0 286px;
  max-width: 286px;
  background: #ffffff;
}

.project-analysis-workspace--sidebar-collapsed .project-analysis-layout__sidebar {
  flex-basis: 46px;
  max-width: 46px;
}

.project-analysis-layout__main {
  flex: 1;
  min-width: 0;
  border-left: 0;
  padding-left: 24px;
  background: #ffffff;
}

.project-analysis-workspace--sidebar-collapsed .project-analysis-layout__main {
  padding-left: 18px;
}

.project-analysis-tabs {
  margin-top: -2px;
}

.external-detail-alert {
  margin-bottom: 12px;
}

.external-detail-loading {
  min-height: 360px;
  border: 1px solid #d9e1ed;
  background: #ffffff;
}
</style>
