<template>
  <div
    class="map-node"
    :class="{
      'linking-source': isLinkingSource,
      'linking-target': isLinkingTarget,
      'drag-over-connect': isDragConnectTarget,
      'drag-over': isDragOver,
      'node-level-red': level === 'red',
      'node-level-yellow': level === 'yellow',
      'node-level-green': level === 'green',
    }"
    :draggable="draggable"
    @dragstart="onDragStart"
    @dragover.prevent="onDragOver"
    @dragleave="onDragLeave"
    @drop.prevent="onDrop"
    @click="onClick"
  >
    <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 }}
    </div>
    <div v-if="objective.description" class="node-desc">{{ objective.description }}</div>
    <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">
      <div class="node-progress-fill"
        :style="{
          width: Math.max(progressData.ratio, 4) + '%',
          background: progressColor(progressData.level)
        }"
      ></div>
      <span class="node-progress-text">
        {{ 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, 2)" :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">
          {{ item.actual != null ? fmtKpiVal(item.actual) : '—' }}
          <span class="snap-target">/ {{ item.target != null ? fmtKpiVal(item.target) : '—' }}</span>
        </span>
      </div>
      <div v-if="progressData.kpiList.length > 2" class="kpi-snapshot-more">
        +{{ progressData.kpiList.length - 2 }} 更多
      </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 { 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
  iconMap?: Record<string, string>
  kpiNameMap?: Record<string, string>
  allKpis?: any[]
}>()

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
}>()

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.7) return 'yellow'
    return 'red'
  }
  return 'gray'
}

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'
}
</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.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);
}
.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; }
.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: 100px; color: #666; }
.snap-value { font-weight: 600; color: #333; white-space: nowrap; }
.snap-target { font-weight: 400; color: #999; font-size: 10px; }
.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: 4px;
  height: 10px; position: relative;
}
.node-progress-fill {
  height: 6px; border-radius: 3px; transition: width 0.4s ease;
  min-width: 4px;
}
.node-progress-text {
  font-size: 10px; font-weight: 600; color: #666;
  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; }
</style>
