<template>
  <div v-loading="loading" class="credit-archive">
    <div class="toolbar">
      <span class="toolbar-label">年报年度：{{ reportYear || '—' }}</span>
      <el-button
        type="text"
        icon="el-icon-refresh"
        style="margin-left: 12px;"
        @click="resetGraph"
      >重置图谱</el-button>
      <span class="toolbar-tip">提示：点击一级分支可展开/收起明细，法定代表人二级节点再次点击可查看相关企业，单分支最多展示 {{ maxNodes }} 个节点</span>
    </div>
    <div ref="graph" class="graph-container" />

    <!-- 节点详情弹窗 -->
    <el-dialog
      :visible.sync="detailVisible"
      :title="detailTitle"
      width="560px"
      append-to-body
    >
      <el-descriptions v-if="detailData" :column="1" border size="small">
        <el-descriptions-item
          v-for="(value, key) in detailData"
          :key="key"
          :label="fieldLabel(key)"
        >{{ formatDetailValue(key, value) }}</el-descriptions-item>
      </el-descriptions>
    </el-dialog>
  </div>
</template>

<script>
import { getCreditArchive, getPersonRelatedEnts } from '@/api/comprehensive'

const MAX_NODES = 20
const DEFAULT_YEAR = new Date().getFullYear() - 1

const FIELD_LABEL_MAP = {
  name: '姓名',
  entName: '企业名称',
  uniscid: '统一社会信用代码',
  certType: '证件类型',
  subConAm: '认缴出资额',
  subConProp: '认缴出资比例（%）',
  respForm: '责任形式',
  position: '职务',
  lerepsign: '法定代表人标志',
  tel: '联系电话',
  email: '电子邮箱',
  invid: '股东ID',
  outinvid: '对外投资ID',
  lmid: '联络员ID',
  specause: '列入原因',
  abntime: '列入日期',
  decorg: '列入决定机关',
  remexcpres: '移出原因',
  remdate: '移出日期',
  status: '状态'
}

const BRANCH_DEFS = [
  { key: 'shareholders', label: '股东信息', color: '#5470c6' },
  { key: 'legalPersons', label: '法定代表人', color: '#91cc75' },
  { key: 'investments', label: '对外投资', color: '#fac858' },
  { key: 'contacts', label: '联络人', color: '#ee6666' },
  { key: 'abnormals', label: '经营异常名录', color: '#fc8452' },
  { key: 'seriousIllegals', label: '严重违法失信', color: '#ea4335' }
]

const ROLE_LABEL_MAP = {
  LEGAL_PERSON: '法人',
  PRINCIPAL_PERSON: '主要人员',
  SHAREHOLDER: '股东',
  OPERATOR: '经营者'
}

export default {
  name: 'CreditArchive',
  props: {
    pripid: {
      type: String,
      required: true
    },
    entName: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      loading: false,
      chart: null,
      reportYear: DEFAULT_YEAR,
      maxNodes: MAX_NODES,
      archiveData: {
        shareholders: [],
        legalPersons: [],
        investments: [],
        contacts: [],
        abnormals: [],
        seriousIllegals: []
      },
      truncated: {
        shareholders: false,
        investments: false,
        contacts: false,
        abnormals: false,
        seriousIllegals: false
      },
      branches: BRANCH_DEFS,
      detailVisible: false,
      detailTitle: '',
      detailData: null
    }
  },
  mounted() {
    this.loadData()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resize)
    if (this.chart) {
      this.chart.dispose()
      this.chart = null
    }
  },
  methods: {
    fieldLabel(key) {
      return FIELD_LABEL_MAP[key] || key
    },
    formatDetailValue(key, value) {
      if (key === 'status') {
        return value === 'IN' ? '在列' : value === 'OUT' ? '已移出' : (value || '—')
      }
      if (key === 'lerepsign') {
        return value === '1' ? '法定代表人' : (value || '—')
      }
      return value || '—'
    },
    async loadData() {
      if (!this.pripid) return
      this.loading = true
      try {
        const res = await getCreditArchive({
          pripid: this.pripid,
          reportYear: this.reportYear
        })
        const data = (res && res.data) || res || {}
        this.archiveData = {
          shareholders: data.shareholders || [],
          legalPersons: data.legalPersons || [],
          investments: data.investments || [],
          contacts: data.contacts || [],
          abnormals: data.abnormals || [],
          seriousIllegals: data.seriousIllegals || []
        }
        this.truncated = data.truncated || {
          shareholders: false,
          investments: false,
          contacts: false,
          abnormals: false,
          seriousIllegals: false
        }
        this.$nextTick(() => this.renderGraph())
      } catch (e) {
        this.$message.error('信用档案数据加载失败')
      } finally {
        this.loading = false
      }
    },
    renderGraph() {
      if (!this.$refs.graph) return
      if (!this.chart) {
        this.chart = this.$echarts.init(this.$refs.graph)
        this.chart.on('click', params => this.handleNodeClick(params))
      }

      const centerName = this.entName || this.archiveData.entName || '主体'
      const centerNode = {
        id: 'center',
        name: centerName,
        symbolSize: 80,
        category: 0,
        fixed: true,
        x: 0,
        y: 0,
        itemStyle: { color: '#409EFF' },
        label: { fontWeight: 'bold' }
      }
      const branchNodes = this.branches.map((b, i) => {
        const list = this.archiveData[b.key] || []
        const count = list.length
        const isTruncated = this.truncated[b.key]
        const label = count === 0
          ? b.label
          : isTruncated
            ? `${b.label} (${MAX_NODES}+)`
            : `${b.label} (${count})`
        return {
          id: b.key,
          name: label,
          symbolSize: 50,
          category: i + 1,
          itemStyle: { color: b.color }
        }
      })
      const branchLinks = this.branches.map(b => ({
        source: 'center',
        target: b.key,
        lineStyle: { color: '#aaa', width: 2 }
      }))

      this.chart.setOption({
        tooltip: {
          trigger: 'item',
          formatter: params => this.formatTooltip(params)
        },
        legend: [{
          data: this.branches.map(b => b.label),
          bottom: 0
        }],
        series: [{
          type: 'graph',
          layout: 'force',
          roam: true,
          draggable: true,
          label: { show: true, position: 'right', formatter: '{b}' },
          force: { repulsion: 400, edgeLength: 120 },
          categories: [
            { name: '主体' },
            ...this.branches.map(b => ({ name: b.label }))
          ],
          data: [centerNode, ...branchNodes],
          links: branchLinks,
          lineStyle: { color: 'source', curveness: 0.1 }
        }]
      }, true)
    },
    formatTooltip(params) {
      if (params.dataType === 'edge') return ''
      const data = params.data
      if (!data) return params.name

      // 三级相关企业节点
      if (data.targetPripid && data.rawData) {
        const ent = data.rawData
        const roles = (ent.roles || []).map(r => ROLE_LABEL_MAP[r] || r).join('、')
        return `${ent.entName || '—'}<br/>角色：${roles}<br/>经营状态：${ent.regstateCn || '—'}`
      }

      // 二级节点 - 经营异常 / 严重违法失信
      if (data.rawData && data.parentKey) {
        const raw = data.rawData
        const branchKey = data.parentKey
        if (branchKey === 'abnormals' || branchKey === 'seriousIllegals') {
          const lines = []
          if (raw.specause) lines.push(`列入原因：${raw.specause}`)
          if (raw.abntime) lines.push(`列入日期：${raw.abntime}`)
          if (raw.decorg) lines.push(`列入决定机关：${raw.decorg}`)
          if (raw.status === 'OUT') {
            if (raw.remexcpres) lines.push(`移出原因：${raw.remexcpres}`)
            if (raw.remdate) lines.push(`移出日期：${raw.remdate}`)
          }
          lines.push(`状态：${raw.status === 'IN' ? '在列' : '已移出'}`)
          return lines.join('<br/>')
        }
      }

      return params.name
    },
    handleNodeClick(params) {
      if (!params.data || params.dataType === 'edge') return
      const data = params.data

      // 一级分支 → toggleBranch
      const branch = this.branches.find(b => b.key === data.id)
      if (branch) {
        this.toggleBranch(branch)
        return
      }

      // 三级相关企业节点 → 新 tab 跳转企业详情
      if (String(data.id).startsWith('rel-')) {
        const pripid = data.targetPripid
        if (pripid) {
          const routeUrl = this.$router.resolve({
            path: '/comprehensive/details',
            query: { pripid }
          }).href
          window.open(routeUrl, '_blank')
        }
        return
      }

      // 二级节点
      if (data.rawData) {
        const parentKey = String(data.id).split('-')[0]

        // 法定代表人二级节点 → 扩展三级「相关企业」
        if (parentKey === 'legalPersons') {
          this.togglePersonRelatedEnts(data)
          return
        }

        // 经营异常 / 严重违法 / 其他 → 弹详情
        this.openDetailDialog(parentKey, data.rawData)
      }
    },
    openDetailDialog(parentKey, rawData) {
      const parentBranch = this.branches.find(b => b.key === parentKey)
      this.detailTitle = parentBranch ? `${parentBranch.label}详情` : '详情'
      this.detailData = rawData
      this.detailVisible = true
    },
    toggleBranch(branch) {
      const list = this.archiveData[branch.key] || []
      if (!list.length) {
        this.$message.info(`暂无${branch.label}`)
        return
      }
      const option = this.chart.getOption()
      const series = option.series[0]
      const prefix = branch.key + '-'
      const hasChild = series.data.some(n => String(n.id).startsWith(prefix))

      if (hasChild) {
        // 收起（同时收起该分支下的三级 rel- 节点）
        series.data = series.data.filter(n => {
          const id = String(n.id)
          return !id.startsWith(prefix) && !(n._parentPrefix && n._parentPrefix.startsWith(prefix))
        })
        series.links = series.links.filter(l => {
          const target = String(l.target)
          return !target.startsWith(prefix) && !(l._parentPrefix && l._parentPrefix.startsWith(prefix))
        })
      } else {
        const displayList = list.slice(0, MAX_NODES)
        const categoryIndex = this.branches.indexOf(branch) + 1
        displayList.forEach((item, i) => {
          const nodeId = `${branch.key}-${i}`
          const nodeData = {
            id: nodeId,
            name: this.getNodeName(branch.key, item, i),
            symbolSize: 30,
            category: categoryIndex,
            itemStyle: {
              color: branch.color,
              opacity: this.getAbnormalOpacity(branch.key, item)
            },
            rawData: item,
            parentKey: branch.key
          }
          series.data.push(nodeData)
          series.links.push({ source: branch.key, target: nodeId })
        })
        const isTruncated = this.truncated[branch.key] || list.length > MAX_NODES
        if (isTruncated) {
          const moreId = `${branch.key}-more`
          series.data.push({
            id: moreId,
            name: `更多... (共 ${list.length}${list.length > MAX_NODES ? '+' : ''} 项)`,
            symbolSize: 26,
            category: categoryIndex,
            itemStyle: { color: branch.color, opacity: 0.4 }
          })
          series.links.push({ source: branch.key, target: moreId })
        }
      }
      this.chart.setOption(option, true)
    },
    getNodeName(key, item, index) {
      if (key === 'investments') return item.entName || '—'
      if (key === 'shareholders') return item.name || '—'
      if (key === 'contacts') return item.name || '—'
      if (key === 'legalPersons') return item.name || '—'
      if (key === 'abnormals') {
        return this.getAbnormalNodeName(item, '经营异常', index)
      }
      if (key === 'seriousIllegals') {
        return this.getAbnormalNodeName(item, '严重违法', index)
      }
      return item.name || '—'
    },
    getAbnormalNodeName(item, fallbackPrefix, index) {
      const cause = item.specause
      const time = item.abntime
      if (cause) {
        const truncatedCause = cause.length > 10 ? cause.substring(0, 10) + '...' : cause
        if (time) {
          const dateStr = this.formatDateToYM(time)
          return `${truncatedCause} (${dateStr})`
        }
        return truncatedCause
      }
      return `${fallbackPrefix} ${index != null ? index + 1 : ''}`.trim()
    },
    getAbnormalOpacity(branchKey, item) {
      if (branchKey === 'abnormals' || branchKey === 'seriousIllegals') {
        return item.status === 'OUT' ? 0.4 : 0.7
      }
      return 0.7
    },
    formatDateToYM(dateVal) {
      if (!dateVal) return ''
      const d = new Date(dateVal)
      if (isNaN(d.getTime())) return String(dateVal).substring(0, 7)
      const y = d.getFullYear()
      const m = String(d.getMonth() + 1).padStart(2, '0')
      return `${y}-${m}`
    },
    async togglePersonRelatedEnts(personNode) {
      const prefix = `rel-${personNode.id}-`
      const option = this.chart.getOption()
      const series = option.series[0]
      const hasChild = series.data.some(n => String(n.id).startsWith(prefix))

      // 已展开 → 收起
      if (hasChild) {
        series.data = series.data.filter(n => !String(n.id).startsWith(prefix))
        series.links = series.links.filter(l => !String(l.target).startsWith(prefix))
        this.chart.setOption(option, true)
        return
      }

      // 调接口
      const person = personNode.rawData
      this.loading = true
      try {
        const res = await getPersonRelatedEnts({
          name: person.name,
          cerno: person.cerno,
          excludePripid: this.pripid
        })
        const data = (res && res.data) || res || {}
        const list = data.ents || []
        if (!list.length) {
          this.$message.info('未查询到该人员的其他相关企业')
          return
        }
        const truncated = !!data.truncated
        const displayList = list.slice(0, MAX_NODES)
        const categoryIndex = this.branches.findIndex(b => b.key === 'legalPersons') + 1
        displayList.forEach((ent, i) => {
          const nodeId = `${prefix}${i}`
          const nodeData = {
            id: nodeId,
            name: this.buildRelatedEntLabel(ent),
            symbolSize: 22,
            category: categoryIndex,
            itemStyle: { color: '#91cc75', opacity: 0.5 },
            targetPripid: ent.pripid,
            rawData: ent,
            _parentPrefix: 'legalPersons-'
          }
          series.data.push(nodeData)
          series.links.push({
            source: personNode.id,
            target: nodeId,
            lineStyle: { type: 'dashed', color: '#91cc75' },
            _parentPrefix: 'legalPersons-'
          })
        })
        if (truncated) {
          const moreId = `${prefix}more`
          series.data.push({
            id: moreId,
            name: `更多... (共 ${displayList.length}+ 项)`,
            symbolSize: 20,
            category: categoryIndex,
            itemStyle: { color: '#91cc75', opacity: 0.3 },
            _parentPrefix: 'legalPersons-'
          })
          series.links.push({
            source: personNode.id,
            target: moreId,
            lineStyle: { type: 'dashed' },
            _parentPrefix: 'legalPersons-'
          })
        }
        this.chart.setOption(option, true)
      } catch (e) {
        this.$message.error('查询相关企业失败')
      } finally {
        this.loading = false
      }
    },
    buildRelatedEntLabel(ent) {
      const name = ent.entName || '—'
      const roles = (ent.roles || []).map(r => ROLE_LABEL_MAP[r] || r)
      if (roles.length) {
        return `${name}(${roles.join('/')})`
      }
      return name
    },
    resetGraph() {
      this.renderGraph()
    },
    resize() {
      if (this.chart) this.chart.resize()
    }
  }
}
</script>

<style lang="scss" scoped>
.credit-archive {
  .toolbar {
    display: flex;
    align-items: center;
    padding: 10px 12px;
    background: #fafafa;
    border: 1px solid #ebeef5;
    border-bottom: none;

    .toolbar-label {
      font-size: 13px;
      color: #606266;
      margin-right: 6px;
    }
    .toolbar-tip {
      margin-left: auto;
      font-size: 12px;
      color: #909399;
    }
  }
  .graph-container {
    width: 100%;
    height: 600px;
    border: 1px solid #ebeef5;
    background: #fff;
  }
}
</style>
