<template>
  <div class="section basic-info-section">
    <div class="section-header">
      <span class="section-icon">&#128176;</span>
      <span class="section-title">成本信息</span>
    </div>
    <div class="section-body">
      <el-descriptions :column="3" border size="small">
        <el-descriptions-item label="囤积成本">
          <span class="cost-value">{{ hoardingCost }}</span>
          <span class="cost-unit">t&#183;天</span>
        </el-descriptions-item>
        <el-descriptions-item label="囤积天数">
          <span>{{ hoardingDays }} 天</span>
        </el-descriptions-item>
        <el-descriptions-item label="钢卷净重">
          <span>{{ coilInfo.netWeight || 0 }} t</span>
        </el-descriptions-item>
      </el-descriptions>

      <div v-if="!pathChecked || pathGraphData.nodes.length > 1" class="cost-chart-wrap">
        <div class="cost-table-title">加工路径</div>

        <div v-if="processedCostTable.length" class="ton-cost-table-wrap">
          <el-table
            :data="processedCostTable"
            border
            size="small"
            :header-cell-style="{ background: '#f5f7fa', color: '#303133', fontWeight: 600 }"
          >
            <el-table-column prop="actionName" label="工序" min-width="120" />
            <el-table-column prop="lineName" label="产线" width="100" />
            <el-table-column prop="coilNo" label="钢卷号" min-width="140" show-overflow-tooltip />
            <el-table-column prop="costPerTon" label="吨钢成本(元/吨)" width="130" align="right">
              <template slot-scope="s">
                <span :class="s.row.costPerTon ? 'cost-ton-val' : 'cost-ton-zero'">{{ s.row.costPerTon || '-' }}</span>
              </template>
            </el-table-column>
            <el-table-column prop="netWeight" label="净重(t)" width="100" align="right">
              <template slot-scope="s">{{ s.row.netWeight }}</template>
            </el-table-column>
            <el-table-column prop="totalCost" label="总成本(元)" width="120" align="right">
              <template slot-scope="s">
                <span class="cost-total-val">{{ s.row.costPerTon ? s.row.totalCost : '-' }}</span>
              </template>
            </el-table-column>
          </el-table>
        </div>

        <div ref="pathChart" v-loading="pathLoading || costLoading" class="path-chart" />
      </div>

      <div v-else-if="!pathLoading && pathChecked" class="cost-chart-wrap">
        <el-empty description="暂无加工路径数据" :image-size="60" />
      </div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import { listPendingAction } from '@/api/wms/pendingAction'
import { getCoilChain } from '@/api/wms/coil'
import { listProdReport } from '@/api/cost/prodReport'
import { listProdMetric } from '@/api/cost/prodMetric'
import { listProdMetricResult } from '@/api/cost/prodMetricResult'

const ACTION_TO_PROD_LINE = {
  11: 2, 120: 2, 201: 2, 520: 2,
  501: 1, 202: 1, 521: 1
}
const PROD_LINE_NAME = { 1: '镀锌产线', 2: '酸轧产线' }

const ACTION_TYPE_MAP = {
  11: '酸连轧工序',
  120: '酸轧分条',

  201: '酸轧合卷',
  202: '镀锌合卷',
  203: '脱脂合卷',
  204: '拉矫平整合卷',
  205: '双机架合卷',
  206: '镀铬合卷',

  501: '镀锌工序',
  502: '脱脂工序',
  503: '拉矫平整工序',
  504: '双机架工序',
  505: '镀铬工序',
  506: '纵剪分条工序',

  520: '酸轧修复工序',
  521: '镀锌修复工序',
  522: '脱脂修复工序',
  523: '拉矫修复工序',
  524: '双机架修复工序',
  525: '镀铬修复工序',

  600: '退火工序'
}

export default {
  name: 'CostInfoSection',
  props: {
    coilInfo: { type: Object, default: () => ({}) },
    traceResult: { type: Object, default: null },
    hoardingDays: { type: Number, default: 0 },
    hoardingCost: { type: [String, Number], default: '0.00' }
  },
  data() {
    return {
      pathLoading: false,
      costLoading: false,
      pathChecked: false,
      chart: null,
      pathGraphData: {
        nodes: [],
        links: []
      },
      processedCostTable: []
    }
  },
  watch: {
    'coilInfo.coilId': {
      handler(val) {
        if (val) {
          this.loadProcessingPath()
        }
      },
      immediate: true
    }
  },
  beforeDestroy() {
    if (this.chart) {
      this.chart.dispose()
      this.chart = null
    }
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    formatVal(val) {
      return val != null ? val : '-'
    },
    async loadProcessingPath() {
      const coilId = this.coilInfo.coilId
      if (!coilId) return

      this.pathLoading = true
      this.pathChecked = false
      try {
        const res = await getCoilChain(coilId)
        const chainData = res.data || {}
        const traceList = chainData.traceList || []

        if (traceList.length <= 1) {
          this.pathGraphData = { nodes: [], links: [] }
          return
        }

        const allCoilIds = []
        traceList.forEach(node => {
          const coil = node.coil
          if (coil && coil.coilId) {
            allCoilIds.push(coil.coilId)
          }
        })

        const actionResults = await Promise.allSettled(
          allCoilIds.map(id => listPendingAction({
            coilId: id,
            actionStatus: 2,
            pageSize: 99999
          }))
        )

        const actionMap = {}
        actionResults.forEach(r => {
          if (r.status === 'fulfilled' && r.value?.rows) {
            r.value.rows.forEach(a => {
              if (a.actionId) {
                actionMap[a.actionId] = a
              }
            })
          }
        })

        if (Object.keys(actionMap).length) {
          const sampleAction = Object.values(actionMap)[0]
          console.log('pendingAction 字段列表：', Object.keys(sampleAction))
          console.log('pendingAction 样例：', sampleAction)
        }

        this.pathGraphData = this.buildGraphData(traceList, coilId, Object.values(actionMap))
        await this.loadCostData()
      } catch (e) {
        console.error('获取加工路径失败：', e)
        this.pathGraphData = { nodes: [], links: [] }
      } finally {
        this.pathLoading = false
        this.pathChecked = true
        this.$nextTick(() => {
          this.initChart()
        })
      }
    },
    buildGraphData(traceList, currentCoilId, actions) {
      const nodes = []
      const links = []
      const nodeIdxMap = {}

      const actionByOutput = {}
      const actionByInput = {}
      function getOutputIds(a) {
        return a.processedCoilIds || a.newCoilIds || a.outputCoilIds ||
          a.completedCoilIds || a.coilIds || ''
      }
      actions.forEach(a => {
        const outIds = getOutputIds(a)
        if (outIds) {
          String(outIds).split(',').forEach(id => {
            const tid = id.trim()
            if (tid) actionByOutput[tid] = a
          })
        }
        if (a.coilId) {
          const key = String(a.coilId)
          if (!actionByInput[key]) actionByInput[key] = a
        }
      })

      // 使用 traceList 自带的 depth，归一化使根节点 level=0
      const depths = traceList.map(n => n.depth != null ? n.depth : 0)
      const minDepth = Math.min(...depths)

      const levelGroups = {}
      traceList.forEach(node => {
        const coil = node.coil
        if (!coil || !coil.coilId) return
        const lv = (node.depth != null ? node.depth : 0) - minDepth
        if (!levelGroups[lv]) levelGroups[lv] = []
        levelGroups[lv].push(coil)
      })

      const levelIndexMap = {}
      Object.keys(levelGroups).forEach(lv => {
        levelGroups[lv].forEach((coil, idx) => {
          levelIndexMap[String(coil.coilId)] = idx
        })
      })

      traceList.forEach(node => {
        const coil = node.coil
        if (!coil || !coil.coilId) return
        const isRoot = !node.parentCoilId
        const isCurrent = String(coil.coilId) === String(currentCoilId)
        const category = isCurrent ? 'current' : (isRoot ? 'root' : 'intermediate')

        const lv = (node.depth != null ? node.depth : 0) - minDepth
        const siblings = levelGroups[lv] || []
        const totalInLevel = siblings.length

        nodeIdxMap[String(coil.coilId)] = nodes.length

        const nodeName = String(coil.currentCoilNo || coil.coilId || '')
        nodes.push({
          name: nodeName,
          id: String(coil.coilId),
          category,
          level: lv,
          levelIndex: levelIndexMap[String(coil.coilId)] || 0,
          levelTotal: totalInLevel,
          symbolSize: 65,
          coilNo: coil.currentCoilNo,
          coilInfo: {
            enterCoilNo: coil.enterCoilNo,
            currentCoilNo: coil.currentCoilNo,
            supplierCoilNo: coil.supplierCoilNo,
            itemName: coil.itemName,
            specification: coil.specification,
            material: coil.material,
            netWeight: coil.netWeight,
            grossWeight: coil.grossWeight,
            warehouseName: coil.warehouseName,
            actualWarehouseName: coil.actualWarehouseName,
            manufacturer: coil.manufacturer,
            zincLayer: coil.zincLayer,
            qualityStatus: coil.qualityStatus,
            surfaceTreatmentDesc: coil.surfaceTreatmentDesc,
            createTime: coil.createTime
          },
          isCurrent
        })
      })

      const nameCount = {}
      nodes.forEach(n => {
        nameCount[n.name] = (nameCount[n.name] || 0) + 1
      })
      const nameUsed = {}
      nodes.forEach(n => {
        if (nameCount[n.name] > 1) {
          nameUsed[n.name] = (nameUsed[n.name] || 0) + 1
          n.name = `${n.name}(${nameUsed[n.name]})`
        }
      })

      traceList.forEach(node => {
        const coil = node.coil
        if (!coil || !coil.coilId) return
        const childIdx = nodeIdxMap[String(coil.coilId)]
        const parentIdStr = node.parentCoilId || (coil.parentCoilId)
        if (!parentIdStr) return

        const parentIds = String(parentIdStr).split(',').map(id => id.trim()).filter(Boolean)
        const action = actionByOutput[String(coil.coilId)] || {}

        parentIds.forEach(pid => {
          const parentIdx = nodeIdxMap[pid]
          if (parentIdx != null && childIdx != null) {
            const edgeAction = Object.keys(action).length ? action
              : (actionByInput[pid] || {})
            const actionTypeVal = edgeAction.actionType != null ? edgeAction.actionType : null
            const actionLabel = ACTION_TYPE_MAP[actionTypeVal] ||
              (actionTypeVal != null ? `工序${actionTypeVal}` : '')

            links.push({
              source: parentIdx,
              target: childIdx,
              label: {
                show: !!actionLabel,
                formatter: actionLabel,
                fontSize: 11,
                color: '#606266'
              },
              actionInfo: {
                actionId: edgeAction.actionId,
                actionType: edgeAction.actionType,
                actionTypeName: actionLabel,
                processTime: edgeAction.processTime,
                completeTime: edgeAction.completeTime,
                createTime: edgeAction.createTime,
                createBy: edgeAction.createBy,
                priority: edgeAction.priority,
                remark: edgeAction.remark
              }
            })
          }
        })
      })

      return { nodes, links }
    },
    async loadCostData() {
      const { nodes, links } = this.pathGraphData
      if (!links.length) return

      this.costLoading = true
      this.processedCostTable = []

      const buildFirstDay = (dateStr) => {
        if (!dateStr) return null
        const d = new Date(dateStr)
        if (isNaN(d.getTime())) return null
        return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`
      }
      const buildDate = (dateStr) => {
        if (!dateStr) return null
        const d = new Date(dateStr)
        if (isNaN(d.getTime())) return null
        return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
      }

      const cache = {}
      const costQueries = links.map(async(link, idx) => {
        const actionType = link.actionInfo?.actionType
        if (actionType == null) return
        const prodLineId = ACTION_TO_PROD_LINE[actionType]
        if (!prodLineId) return

        const targetNode = nodes[link.target]
        const createTime = targetNode?.coilInfo?.createTime
        if (!createTime) return

        const firstDay = buildFirstDay(createTime)
        const prodDate = buildDate(createTime)
        if (!firstDay || !prodDate) return

        const cacheKey = `${prodLineId}_${firstDay}`

        try {
          let rpMetric = cache[cacheKey]
          if (rpMetric === undefined) {
            const rpRes = await listProdReport({ lineType: prodLineId, reportDate: firstDay, pageNum: 1, pageSize: 10 })
            const reports = rpRes?.rows || []
            if (reports.length !== 1) { cache[cacheKey] = null; return }
            const reportId = reports[0].reportId

            const mRes = await listProdMetric({ reportId, pageNum: 1, pageSize: 9999, tags: '吨钢成本' })
            const metrics = (mRes?.rows || []).filter(m => (m.tags || '').includes('吨钢成本'))
            if (metrics.length !== 1) { cache[cacheKey] = null; return }

            rpMetric = { reportId, metricId: metrics[0].metricId }
            cache[cacheKey] = rpMetric
          }
          if (!rpMetric) return

          const rRes = await listProdMetricResult({
            reportId: rpMetric.reportId,
            metricId: rpMetric.metricId,
            metricDate: prodDate,
            pageNum: 1, pageSize: 10
          })
          const results = rRes?.rows || []
          const costPerTon = results.length > 0 ? parseFloat(results[0].calcValue) || 0 : 0

          link.costPerTon = costPerTon
          link.lineName = PROD_LINE_NAME[prodLineId] || ''

          const netWeight = parseFloat(targetNode.coilInfo.netWeight) || 0
          this.processedCostTable.push({
            idx,
            actionName: link.actionInfo?.actionTypeName || link.label?.formatter || '',
            lineName: link.lineName,
            coilNo: targetNode.coilNo || targetNode.name || '',
            costPerTon,
            netWeight,
            totalCost: Math.round(costPerTon * netWeight * 100) / 100
          })
        } catch (e) {
          console.error('查询吨钢成本失败(actionType=' + actionType + '):', e)
        }
      })

      await Promise.allSettled(costQueries)
      this.costLoading = false
    },
    initChart() {
      if (this.chart) {
        this.chart.dispose()
        this.chart = null
      }

      const dom = this.$refs.pathChart
      if (!dom) return
      const { nodes, links } = this.pathGraphData
      if (!nodes.length) return

      const containerWidth = dom.clientWidth || 800

      const maxLevel = Math.max(...nodes.map(n => n.level || 0), 0)
      const totalLevels = maxLevel + 1

      const levelGroups = {}
      nodes.forEach(n => {
        const lv = n.level || 0
        if (!levelGroups[lv]) levelGroups[lv] = []
        levelGroups[lv].push(n)
      })

      const maxNodesInLevel = Math.max(...Object.values(levelGroups).map(g => g.length), 1)
      const paddingX = 100
      const paddingY = 70

      const LEVEL_GAP_X = totalLevels > 1
        ? Math.max(240, (containerWidth - paddingX * 2) / (totalLevels - 1))
        : 240
      const LEVEL_GAP_Y = 110

      const START_X = paddingX
      const START_Y = paddingY

      nodes.forEach(n => {
        const lv = n.level || 0
        const sibIdx = n.levelIndex != null ? n.levelIndex : 0
        const totalInLevel = n.levelTotal || 1
        n.x = START_X + lv * LEVEL_GAP_X
        n.y = START_Y + (sibIdx - (totalInLevel - 1) / 2) * LEVEL_GAP_Y
      })

      const chartHeight = Math.max(350, maxNodesInLevel * LEVEL_GAP_Y + paddingY * 2)

      dom.style.width = containerWidth + 'px'
      dom.style.height = chartHeight + 'px'

      this.chart = echarts.init(dom)

      const rootGradient = { type: 'radial', x: 0.5, y: 0.5, r: 0.5, colorStops: [{ offset: 0, color: '#93c5fd' }, { offset: 1, color: '#3b82f6' }] }
      const intermediateGradient = { type: 'radial', x: 0.5, y: 0.5, r: 0.5, colorStops: [{ offset: 0, color: '#6ee7b7' }, { offset: 1, color: '#10b981' }] }
      const currentGradient = { type: 'radial', x: 0.5, y: 0.5, r: 0.5, colorStops: [{ offset: 0, color: '#fde68a' }, { offset: 1, color: '#f59e0b' }] }

      const gradientMap = {
        root: rootGradient,
        intermediate: intermediateGradient,
        current: currentGradient
      }

      const option = {
        tooltip: {
          trigger: 'item',
          confine: true,
          backgroundColor: 'rgba(20,20,30,0.92)',
          borderColor: '#3b82f6',
          borderWidth: 1,
          borderRadius: 8,
          padding: [10, 14],
          textStyle: { color: '#e5e7eb', fontSize: 12 },
          formatter: (params) => {
            if (params.dataType === 'edge') {
              const ai = params.data.actionInfo || {}
              const cp = params.data.costPerTon
              const rows = [
                `<div style="font-weight:bold;color:#fbbf24;margin-bottom:4px;font-size:13px">${ai.actionTypeName || '工序'}</div>`
              ]
              if (cp) rows.push(`<span style="color:#34d399">吨钢成本</span>：${cp} 元/吨`)
              let hasInfo = false
              if (ai.processTime) { rows.push(`处理时间：${ai.processTime}`); hasInfo = true }
              if (ai.completeTime) { rows.push(`完成时间：${ai.completeTime}`); hasInfo = true }
              if (ai.createTime) { rows.push(`创建时间：${ai.createTime}`); hasInfo = true }
              if (ai.createBy) { rows.push(`创建人：${ai.createBy}`); hasInfo = true }
              if (!cp && !hasInfo) return ''
              return rows.join('<br/>')
            }
            const d = params.data
            const ci = d.coilInfo || {}
            const badge = d.isCurrent ? '<span style="display:inline-block;background:#f59e0b;color:#fff;padding:1px 6px;border-radius:4px;font-size:11px;margin-left:6px">当前卷</span>' : ''
            const rows = [
              `<div style="font-weight:bold;color:#60a5fa;margin-bottom:4px;font-size:13px">${ci.currentCoilNo || '-'}${badge}</div>`
            ]
            if (ci.enterCoilNo) rows.push(`<span style="color:#9ca3af">入场钢卷号</span>：${ci.enterCoilNo}`)
            if (ci.supplierCoilNo) rows.push(`<span style="color:#9ca3af">厂家原料号</span>：${ci.supplierCoilNo}`)
            if (ci.itemName) rows.push(`<span style="color:#9ca3af">物料名</span>：${ci.itemName}`)
            if (ci.specification) rows.push(`<span style="color:#9ca3af">规格</span>：${ci.specification}`)
            if (ci.material) rows.push(`<span style="color:#9ca3af">材质</span>：${ci.material}`)
            if (ci.netWeight != null) rows.push(`<span style="color:#9ca3af">净重</span>：${ci.netWeight} t`)
            if (ci.manufacturer) rows.push(`<span style="color:#9ca3af">厂家</span>：${ci.manufacturer}`)
            if (ci.warehouseName) rows.push(`<span style="color:#9ca3af">逻辑库位</span>：${ci.warehouseName}`)
            if (ci.actualWarehouseName) rows.push(`<span style="color:#9ca3af">实际库区</span>：${ci.actualWarehouseName}`)
            if (ci.zincLayer) rows.push(`<span style="color:#9ca3af">镀层质量</span>：${ci.zincLayer}`)
            if (ci.qualityStatus) rows.push(`<span style="color:#9ca3af">质量状态</span>：${ci.qualityStatus}`)
            if (ci.surfaceTreatmentDesc) rows.push(`<span style="color:#9ca3af">表面处理</span>：${ci.surfaceTreatmentDesc}`)
            if (ci.createTime) rows.push(`<span style="color:#9ca3af">创建时间</span>：${ci.createTime}`)
            if (ci.createBy) rows.push(`<span style="color:#9ca3af">创建人</span>：${ci.createBy}`)
            return rows.join('<br/>')
          }
        },
        animationDuration: 1000,
        animationEasing: 'cubicOut',
        animationEasingUpdate: 'quinticInOut',
        series: [
          {
            type: 'graph',
            layout: 'none',
            roam: true,
            draggable: false,
            data: nodes.map(n => ({
              name: n.name,
              x: n.x,
              y: n.y,
              symbol: 'roundRect',
              symbolSize: n.symbolSize,
              category: undefined,
              itemStyle: {
                color: gradientMap[n.category] || '#909399',
                borderColor: n.isCurrent ? '#f59e0b' : 'rgba(255,255,255,0.6)',
                borderWidth: n.isCurrent ? 4 : 2,
                shadowBlur: n.isCurrent ? 20 : 8,
                shadowColor: n.isCurrent ? 'rgba(245,158,11,0.55)' : 'rgba(0,0,0,0.2)',
                shadowOffsetY: 2
              },
              label: {
                show: true,
                formatter: (p) => {
                  const cn = p.data.coilNo || p.data.name
                  return cn && cn.length > 12 ? cn.slice(0, 11) + '...' : (cn || '-')
                },
                fontSize: 11,
                fontWeight: n.isCurrent ? 'bold' : 'normal',
                color: n.isCurrent ? '#f59e0b' : '#374151',
                position: 'bottom',
                distance: 8
              },
              emphasis: {
                scale: 1.2,
                itemStyle: {
                  shadowBlur: n.isCurrent ? 30 : 20,
                  shadowColor: n.isCurrent ? 'rgba(245,158,11,0.7)' : 'rgba(59,130,246,0.5)',
                  borderWidth: n.isCurrent ? 5 : 3
                }
              },
              coilNo: n.coilNo,
              coilInfo: n.coilInfo,
              isCurrent: n.isCurrent
            })),
            links: links.map(l => ({
              source: l.source,
              target: l.target,
              label: {
                show: !!(l.label && l.label.formatter) || !!l.costPerTon,
                formatter: (l.costPerTon != null)
                  ? `${l.label && l.label.formatter ? l.label.formatter + '  ' : ''}${l.costPerTon}元/吨`
                  : (l.label && l.label.formatter ? l.label.formatter : ''),
                fontSize: 11,
                color: l.costPerTon != null ? '#059669' : '#606266'
              },
              lineStyle: {
                color: l.costPerTon != null ? 'rgba(5,150,105,0.6)' : 'rgba(107,114,128,0.55)',
                width: l.costPerTon != null ? 3 : 2.5,
                curveness: 0.15,
                cap: 'round',
                opacity: 0.9
              },
              emphasis: {
                lineStyle: {
                  color: '#3b82f6',
                  width: 4,
                  opacity: 1
                },
                label: {
                  fontSize: 12,
                  fontWeight: 'bold',
                  color: '#2563eb'
                }
              },
              actionInfo: l.actionInfo,
              costPerTon: l.costPerTon
            })),
            edgeSymbol: ['none', 'arrow'],
            edgeSymbolSize: [0, 12],
            edgeLabel: {
              show: true,
              fontSize: 11,
              color: '#4b5563',
              position: 'middle',
              backgroundColor: 'rgba(255,255,255,0.85)',
              borderRadius: 4,
              padding: [2, 6],
              distance: 6
            },
            categories: [
              { name: 'root', itemStyle: { color: '#3b82f6' }},
              { name: 'intermediate', itemStyle: { color: '#10b981' }},
              { name: 'current', itemStyle: { color: '#f59e0b' }}
            ]
          }
        ]
      }

      this.chart.setOption(option)
      this.handleResize = () => {
        if (this.chart && !this.chart.isDisposed()) {
          this.chart.resize()
        }
      }
      window.addEventListener('resize', this.handleResize)
    }
  }
}
</script>

<style scoped>
.cost-value {
  font-weight: 600;
  color: #f56c6c;
}

.cost-unit {
  font-size: 12px;
  color: #909399;
  margin-left: 2px;
}

.cost-chart-wrap {
  margin-top: 12px;
}

.cost-table-title {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
  padding: 6px 0;
  border-bottom: 1px solid #ebeef5;
  margin-bottom: 8px;
}

.path-chart {
  width: 100%;
  min-height: 300px;
}

.ton-cost-table-wrap {
  margin-bottom: 12px;
}

.cost-ton-val {
  font-weight: 600;
  color: #059669;
}

.cost-ton-zero {
  color: #c0c4cc;
}

.cost-total-val {
  font-weight: 600;
  color: #f56c6c;
}
</style>
