<template>
  <div
    class="map-node"
    :class="{
      'linking-source': isLinkingSource,
      'linking-target': isLinkingTarget,
      'drag-over-connect': isDragConnectTarget,
      'drag-over': isDragOver,
      'link-valid-target': linkEligibility === 'valid',
      'link-forbidden': linkEligibility === 'forbidden',
      'node-level-red': level === 'red',
      'node-level-yellow': level === 'yellow',
      'node-level-green': level === 'green',
      'kr-expanded': krExpanded,
      'chain-dimmed': chainDimmed,
    }"
    :draggable="draggable"
    @dragstart="onDragStart"
    @dragover.prevent="onDragOver"
    @dragleave="onDragLeave"
    @drop.prevent="onDrop"
    @click="onClick"
  >
    <!-- O标题行 -->
    <div class="node-title">
      <span class="node-level-dot" :class="'dot-' + (level || 'gray')"></span>
      <el-icon v-if="objIcon" style="margin-right:4px;"><component :is="objIcon" /></el-icon>
      {{ objective.name }}
      <!-- KR折叠/展开按钮 -->
      <span
        v-if="hasKrs"
        class="kr-toggle-btn"
        @click.stop="krExpanded = !krExpanded"
        :title="krExpanded ? '收起关键结果' : '展开关键结果'"
      >
        {{ krExpanded ? '▲' : '▼' }}
        <span class="kr-toggle-count">{{ objective.krs.length }}条KR</span>
      </span>
    </div>
    <div v-if="objective.description" class="node-desc">{{ objective.description }}</div>

    <!-- KR子节点列表（展开时显示） -->
    <div v-if="hasKrs && krExpanded" class="kr-sub-list">
      <div
        v-for="(kr, ki) in objective.krs"
        :key="ki"
        class="kr-sub-item"
        @click.stop="$emit('edit-kr', { index: ki, kr })"
      >
        <div class="kr-sub-top">
          <span class="kr-sub-index">{{ ki + 1 }}</span>
          <span class="kr-sub-name" :title="kr.name">{{ kr.name }}</span>
          <span v-if="kr.target_value" class="kr-sub-target">目标: {{ kr.target_value }}</span>
        </div>
        <div class="kr-sub-bottom">
          <div class="kr-sub-progress-wrap">
            <div class="kr-sub-progress-bg">
              <div
                class="kr-sub-progress-fill"
                :style="{ width: getKrProgress(kr) + '%', background: getKrProgressColor(kr) }"
              ></div>
            </div>
            <span class="kr-sub-progress-text">{{ getKrProgressText(kr) }}</span>
          </div>
          <span v-if="kr.weight" class="kr-sub-weight">{{ kr.weight }}%</span>
        </div>
      </div>
      <!-- 底部+KR按钮 -->
      <el-button size="small" type="primary" plain class="kr-add-btn" @click.stop="$emit('add-kr')">
        + KR
      </el-button>
    </div>

    <!-- 无KR时的展开提示 -->
    <div v-if="!hasKrs && krExpanded" class="kr-empty-hint" @click.stop>
      <span>暂无关键结果</span>
      <el-button size="small" type="primary" plain @click.stop="$emit('add-kr')">+ 添加KR</el-button>
    </div>

    <!-- 原有KPI展示 -->
    <div class="node-kpis">
      <el-tag
        v-for="kpi in (objective.kpis||[])" :key="kpi"
        size="small" style="margin:2px;cursor:pointer;"
        :title="kpi"
        @click.stop="$emit('kpi-click', kpi)"
      >{{ getKpiName(kpi) }}</el-tag>
    </div>
    <!-- KPI达成率迷你进度条（右下角） -->
    <div v-if="progressData" class="node-progress-bar">
      <span class="node-progress-label">达成率</span>
      <div class="node-progress-track">
        <div class="node-progress-fill"
          :style="{
            width: Math.max(progressData.ratio, 4) + '%',
            background: progressColor(progressData.level)
          }"
        ></div>
      </div>
      <span class="node-progress-text" :style="{ color: progressColor(progressData.level) }">
        {{ progressData.ratio > 0 ? progressData.ratio + '%' : '—' }}
      </span>
    </div>
    <!-- KPI实际值快照：当前值 / 目标值 / 达成率 -->
    <div v-if="progressData?.kpiList?.length" class="node-kpi-snapshots">
      <div
        v-for="item in progressData.kpiList.slice(0, 3)" :key="item.code"
        class="kpi-snapshot-row"
        :class="'snap-' + getKpiLevel(item)"
      >
        <span class="snap-name" :title="item.name">{{ item.name }}</span>
        <span class="snap-value">
          <span class="snap-now" :class="'snap-now-' + getKpiLevel(item)">{{ item.actual != null ? fmtKpiVal(item.actual) : '—' }}</span>
          <span class="snap-target">/ {{ item.target != null ? fmtKpiVal(item.target) : '—' }}</span>
        </span>
        <span class="snap-rate" :class="'rate-' + getKpiLevel(item)">{{ kpiRateText(item) }}</span>
      </div>
      <div v-if="progressData.kpiList.length > 3" class="kpi-snapshot-more">
        +{{ progressData.kpiList.length - 3 }} 更多
      </div>
    </div>
    <div v-if="progressData?.kpiList?.length" class="node-click-hint">点击查看KPI详情</div>
    <!-- 行动方案摘要 -->
    <div v-if="progressData?.planSummary" class="node-plan-summary" @click.stop="$emit('plan-click')">
      <span class="plan-summary-icon">📋</span>
      <span class="plan-summary-text">{{ progressData.planSummary.total }} 项行动方案</span>
      <span class="plan-summary-badges">
        <span v-if="progressData.planSummary.overdue > 0" class="ps-badge ps-overdue">{{ progressData.planSummary.overdue }}逾期</span>
        <span v-if="progressData.planSummary.in_progress > 0" class="ps-badge ps-in-progress">{{ progressData.planSummary.in_progress }}进行中</span>
        <span v-if="progressData.planSummary.completed === progressData.planSummary.total && progressData.planSummary.total > 0" class="ps-badge ps-done">全部完成 ✅</span>
      </span>
    </div>
    <!-- 右上角连线入口 -->
    <span class="link-btn-corner"
      @mousedown.prevent="$emit('link-drag-start', $event)"
      @click.stop="$emit('link-click')"
      title="拖拽到另一个目标创建因果连线">↗</span>
    <div class="node-actions">
      <el-button text size="small" @click.stop="$emit('edit')" title="编辑目标">✏️</el-button>
      <el-button text size="small" @click.stop="$emit('delete')" title="删除目标" style="color:#f56c6c;">🗑️</el-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'

const props = defineProps<{
  objective: any
  nodeKey: string
  level?: string
  progressData?: any
  index: number
  draggable?: boolean
  isLinkingSource?: boolean
  isLinkingTarget?: boolean
  isDragConnectTarget?: boolean
  isDragOver?: boolean
  /** 拖拽连线目标合法性：valid=合法高亮 / forbidden=反方向灰显不可连 */
  linkEligibility?: 'valid' | 'forbidden' | null
  iconMap?: Record<string, string>
  kpiNameMap?: Record<string, string>
  allKpis?: any[]
  /** 因果链查看模式下不在链上 → 变淡 */
  chainDimmed?: boolean
}>()

const emit = defineEmits<{
  (e: 'drag-start', payload: { index: number; event: DragEvent }): void
  (e: 'drag-over'): void
  (e: 'drag-leave'): void
  (e: 'drop'): void
  (e: 'click'): void
  (e: 'edit'): void
  (e: 'delete'): void
  (e: 'link-click'): void
  (e: 'link-drag-start', event: MouseEvent): void
  (e: 'kpi-click', kpiCode: string): void
  (e: 'plan-click'): void
  (e: 'edit-kr', payload: { index: number; kr: any }): void
  (e: 'add-kr'): void
}>()

// KR展开/折叠状态
const krExpanded = ref(true)

const hasKrs = computed(() => {
  return props.objective?.krs && Array.isArray(props.objective.krs) && props.objective.krs.length > 0
})

const objIcon = computed(() => {
  if (props.objective.icon && props.iconMap) {
    return (props.iconMap as Record<string, string>)[props.objective.icon]
  }
  return null
})

function onDragStart(e: DragEvent) {
  emit('drag-start', { index: props.index, event: e })
}
function onDragOver() { emit('drag-over') }
function onDragLeave() { emit('drag-leave') }
function onDrop() { emit('drop') }
function onClick() { emit('click') }

function getKpiName(code: string): string {
  if (props.kpiNameMap && props.kpiNameMap[code]) return props.kpiNameMap[code]
  const k = props.allKpis?.find((k: any) => k.kpi_code === code)
  return k?.kpi_name || code
}

function getKpiLevel(item: any): string {
  if (item.actual != null && item.target) {
    const ratio = item.actual / item.target
    if (ratio >= 0.9) return 'green'
    if (ratio >= 0.6) return 'yellow'
    return 'red'
  }
  return 'gray'
}

/** KPI达成率文本（绿≥90% / 黄60-90% / 红<60%） */
function kpiRateText(item: any): string {
  if (item.actual == null || !item.target) return '—'
  const ratio = item.actual / item.target
  return Math.round(ratio * 100) + '%'
}

function fmtKpiVal(val: any): string {
  if (val == null) return '—'
  if (typeof val === 'number') {
    if (Math.abs(val) >= 10000) return (val / 10000).toFixed(1) + '万'
    return val.toLocaleString()
  }
  return String(val)
}

function progressColor(level: string): string {
  if (level === 'green') return '#67c23a'
  if (level === 'yellow') return '#e6a23c'
  if (level === 'red') return '#f56c6c'
  return '#dcdfe6'
}

// KR进度计算
function getKrProgress(kr: any): number {
  if (kr.current_value != null && kr.target_value) {
    const target = parseFloat(String(kr.target_value).replace(/[≥≤>]/g, '').replace(/[^0-9.]/g, ''))
    const current = parseFloat(String(kr.current_value))
    if (!isNaN(target) && target > 0 && !isNaN(current)) {
      return Math.min(100, Math.round((current / target) * 100))
    }
  }
  return 0
}

function getKrProgressColor(kr: any): string {
  const pct = getKrProgress(kr)
  if (pct >= 90) return '#67c23a'
  if (pct >= 60) return '#e6a23c'
  if (pct > 0) return '#f56c6c'
  return '#dcdfe6'
}

function getKrProgressText(kr: any): string {
  const pct = getKrProgress(kr)
  if (pct > 0) return pct + '%'
  if (kr.current_value != null) return String(kr.current_value)
  return '—'
}
</script>

<style scoped>
.map-node {
  background: #fff; border: 1px solid #e0e0e0; border-radius: 8px;
  padding: 10px; margin-bottom: 8px; cursor: pointer;
  transition: all 0.2s; position: relative;
}
.map-node:hover { box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.map-node.chain-dimmed {
  opacity: 0.3;
  filter: saturate(0.35);
  pointer-events: auto;
}
.map-node.linking-source {
  border-color: #e6a23c; box-shadow: 0 0 0 2px rgba(230,162,60,0.3);
}
.map-node.linking-target:hover {
  border-color: #67c23a; box-shadow: 0 0 0 2px rgba(103,194,58,0.3);
}
.map-node.drag-over-connect {
  border-color: #67c23a !important; box-shadow: 0 0 0 3px rgba(103,194,58,0.5) !important;
  transform: scale(1.03);
}
.map-node.drag-over {
  border-color: #409eff !important; box-shadow: 0 0 0 2px rgba(64,158,255,0.3) !important;
  transform: scale(1.02);
}
/* 拖拽连线：合法目标高亮（绿色呼吸） */
.map-node.link-valid-target {
  border-color: #67c23a !important;
  box-shadow: 0 0 0 2px rgba(103,194,58,0.45), 0 0 8px rgba(103,194,58,0.35);
  animation: link-valid-pulse 1.2s ease-in-out infinite;
}
@keyframes link-valid-pulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(103,194,58,0.45), 0 0 8px rgba(103,194,58,0.3); }
  50% { box-shadow: 0 0 0 3px rgba(103,194,58,0.7), 0 0 14px rgba(103,194,58,0.5); }
}
/* 拖拽连线：反方向目标灰显不可连 */
.map-node.link-forbidden {
  opacity: 0.38;
  filter: grayscale(0.7);
  cursor: not-allowed;
}
.node-level-red { border-left: 3px solid #f56c6c !important; background: #fef0f0; }
.node-level-yellow { border-left: 3px solid #e6a23c !important; background: #fdf6ec; }
.node-level-green { border-left: 3px solid #67c23a !important; background: #f0f9eb; }
.node-title { font-size: 13px; font-weight: 500; margin-bottom: 4px; display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
.node-desc { font-size: 12px; color: #888; margin-bottom: 4px; }
.node-kpis { display: flex; flex-wrap: wrap; gap: 2px; }

.node-kpi-snapshots { margin-top: 4px; display: flex; flex-direction: column; gap: 2px; }
.kpi-snapshot-row {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 11px; padding: 1px 4px; border-radius: 3px;
}
.snap-green { background: #f0f9eb; }
.snap-yellow { background: #fdf6ec; }
.snap-red { background: #fef0f0; }
.snap-gray { background: #f5f5f5; }
.snap-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 92px; color: #666; }
.snap-value {
  font-weight: 600; color: #333; white-space: nowrap;
  font-family: 'JetBrains Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-variant-numeric: tabular-nums;
}
.snap-now-green { color: #67c23a; }
.snap-now-yellow { color: #e6a23c; }
.snap-now-red { color: #f56c6c; }
.snap-now-gray { color: #333; }
.snap-target { font-weight: 400; color: #999; font-size: 10px; }
.snap-rate {
  font-size: 10px; font-weight: 700; flex-shrink: 0; min-width: 34px; text-align: right;
  font-family: 'JetBrains Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-variant-numeric: tabular-nums;
}
.rate-green { color: #67c23a; }
.rate-yellow { color: #e6a23c; }
.rate-red { color: #f56c6c; }
.rate-gray { color: #bbb; }
.kpi-snapshot-more { font-size: 10px; color: #409eff; text-align: center; cursor: pointer; padding: 1px; }
.node-click-hint { font-size: 10px; color: #bbb; text-align: center; margin-top: 2px; }

.node-plan-summary {
  display: flex; align-items: center; gap: 6px;
  margin-top: 4px; padding: 4px 6px;
  background: #f8f9fa; border-radius: 4px;
  font-size: 11px; cursor: pointer; transition: background .15s;
}
.node-plan-summary:hover { background: #ecf5ff; }
.plan-summary-icon { font-size: 12px; }
.plan-summary-text { color: #409eff; font-weight: 500; flex-shrink: 0; }
.plan-summary-badges { display: flex; gap: 4px; margin-left: auto; }
.ps-badge { font-size: 10px; padding: 1px 5px; border-radius: 3px; font-weight: 500; }
.ps-overdue { background: #fef0f0; color: #f56c6c; }
.ps-in-progress { background: #fdf6ec; color: #e6a23c; }
.ps-done { background: #f0f9eb; color: #67c23a; }

.node-progress-bar {
  display: flex; align-items: center; gap: 6px; margin-top: 6px;
  justify-content: flex-end;
}
.node-progress-label {
  font-size: 10px; color: #909399; flex-shrink: 0; line-height: 1;
}
.node-progress-track {
  flex: 1; max-width: 90px; height: 6px; background: #e4e7ed;
  border-radius: 3px; overflow: hidden;
}
.node-progress-fill {
  height: 100%; border-radius: 3px; transition: width 0.4s ease;
  min-width: 4px;
}
.node-progress-text {
  font-size: 10px; font-weight: 700; min-width: 34px; text-align: right;
  font-family: 'JetBrains Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-variant-numeric: tabular-nums; line-height: 1;
}

.node-actions { display: flex; align-items: center; gap: 2px; margin-top: 6px; justify-content: flex-end; position: relative; z-index: 20; }
.node-actions .el-button { padding: 2px 4px !important; font-size: 12px; min-height: auto; }

.link-btn-corner {
  position: absolute; top: 4px; right: 6px;
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
  background: #ecf5ff; color: #409eff; border-radius: 50%;
  font-size: 14px; font-weight: bold; cursor: pointer; opacity: 0;
  transition: opacity .2s, transform .2s;
}
.map-node:hover .link-btn-corner { opacity: 1; }
.link-btn-corner:hover { transform: scale(1.2); background: #409eff; color: #fff; }

.node-level-dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 4px; flex-shrink: 0;
}
.dot-green { background: #67c23a; }
.dot-yellow { background: #e6a23c; }
.dot-red { background: #f56c6c; }
.dot-gray { background: #dcdfe6; }

/* ── KR子节点样式 ── */
.kr-toggle-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: #409eff;
  cursor: pointer;
  margin-left: 8px;
  padding: 1px 6px;
  border-radius: 4px;
  background: #ecf5ff;
  user-select: none;
  transition: background .15s;
}
.kr-toggle-btn:hover {
  background: #d9ecff;
}
.kr-toggle-count {
  font-weight: 400;
}

.kr-sub-list {
  margin-top: 6px;
  border-top: 1px dashed #e4e7ed;
  padding-top: 6px;
}
.kr-sub-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 6px 8px;
  margin-bottom: 4px;
  border-radius: 6px;
  border: 1px solid #e8f0fe;
  background: #f8faff;
  cursor: pointer;
  transition: all 0.15s;
}
.kr-sub-item:hover {
  background: #ecf5ff;
  border-color: #409eff;
}
.kr-sub-top {
  display: flex;
  align-items: center;
  gap: 6px;
}
.kr-sub-index {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #409eff;
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.kr-sub-name {
  flex: 1;
  font-size: 12px;
  font-weight: 500;
  color: #303133;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kr-sub-target {
  font-size: 10px;
  color: #909399;
  flex-shrink: 0;
}
.kr-sub-bottom {
  display: flex;
  align-items: center;
  gap: 8px;
}
.kr-sub-progress-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 6px;
}
.kr-sub-progress-bg {
  flex: 1;
  height: 6px;
  background: #e4e7ed;
  border-radius: 3px;
  overflow: hidden;
}
.kr-sub-progress-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease;
}
.kr-sub-progress-text {
  font-size: 10px;
  font-weight: 600;
  color: #606266;
  min-width: 28px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.kr-sub-weight {
  font-size: 10px;
  color: #909399;
  background: #f0f5ff;
  padding: 1px 6px;
  border-radius: 8px;
  flex-shrink: 0;
}
.kr-empty-hint {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding: 8px;
  color: #909399;
  font-size: 12px;
  border-top: 1px dashed #e4e7ed;
}
.kr-add-btn {
  width: 100% !important;
  margin-top: 2px;
}
</style>
