import { init, use } from 'echarts/core'
import { LineChart } from 'echarts/charts'
import { GridComponent, MarkLineComponent } from 'echarts/components'
import { SVGRenderer } from 'echarts/renderers'
import { getSplicePrintVersion, spliceFields, spliceFieldValue, spliceStatisticKey, spliceSourceValue, spliceExperiment, spliceSourceFields, spliceDetailValue, type SavedSpliceReport } from '@/api/spliceReports'
import { openSavedReportPrint } from './savedReportPrint'
import css from './spliceSavedReport.css?inline'

use([LineChart, GridComponent, MarkLineComponent, SVGRenderer])
const metrics = [
  { key: 'finalVoltage1', title: '最终电压1', unit: 'V' },
  { key: 'energyEfficiency', title: '能量效率', unit: '%' },
]
function escapeHtml(value: unknown) {
  const entities: Record<string, string> = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }
  return String(value ?? '').replace(/[&<>"']/g, character => entities[character]!)
}
const cell = (value: unknown) => escapeHtml(value == null || value === '' ? '缺失' : value)
const numeric = (value: unknown) => typeof value === 'number' && Number.isFinite(value) ? value : null
const display = (value: unknown) => { const number = numeric(value); return number === null ? '缺失' : String(Number(number.toFixed(4))) }

/** 重开与打印共用冻结统计及人工字段，绝不重算或读取来源测试。 */
export function spliceSavedReportBody(record: SavedSpliceReport, chartsOnly = false) {
  if (record.spliceMode === 'battery-segments') return segmentReportBody(record, chartsOnly)
  const sources = [...new Set(record.segments.map(segment => segment.source.selection.testId))]
  const batteries = [...new Set(record.segments.map(segment => segment.source.batteryNo))]
  const color = (battery: string) => {
    const index = batteries.indexOf(battery)
    const saved = record.settings.seriesColors?.[index]
    return saved && /^#[\da-f]{6}$/i.test(saved) ? saved : ['#3978f6', '#109854', '#d25b45', '#7754a8'][index % 4]!
  }
  const label = (testId: number) => `来源${sources.indexOf(testId) + 1}`
  const fields = spliceFields(record.settings)
  // 早期版本的五类实时显隐键不适用于循环统计，不能据此补造测量曲线。
  const savedMetrics = record.settings.metrics
  const visibleMetrics = savedMetrics?.some(key => metrics.some(metric => metric.key === key)) || savedMetrics?.length === 0
    ? metrics.filter(metric => savedMetrics!.includes(metric.key)) : metrics
  const sourceRows = record.segments.map(segment => `<tr><td>${label(segment.source.selection.testId)}</td><td>${cell(segment.source.name)}</td><td>${cell(segment.source.group)}</td><td>${cell(segment.source.batteryNo)}</td><td>${segment.originalCycleNos.map(no => `${no} → ${segment.offset + no}`).join('、') || '无已保存循环'}</td></tr>`).join('')
  const fieldRows = batteries.flatMap(battery => fields.map(field => `<tr><td>${cell(battery)}</td><td>${cell(field.displayName)}${field.unit ? ` (${escapeHtml(field.unit)})` : ''}</td><td>${cell(spliceFieldValue(record.segments, record.settings, field, battery))}</td></tr>`)).join('')
  const statistics = sources.map(testId => {
    const segments = record.segments.filter(segment => segment.source.selection.testId === testId)
    const rows = segments.flatMap(segment => segment.originalCycleNos.map(no => {
      const stat = segment.statistics[String(no)] ?? {}
      return `<tr><td>${cell(segment.source.batteryNo)}</td><td>${no}</td><td>${segment.offset + no}</td>${metrics.map(metric => {
        const override = record.settings.statisticValues?.[spliceStatisticKey(segment, no, metric.key)]
        return `<td>${override === undefined ? display(stat[metric.key]) : `${cell(override)}<br><small>计算原值：${display(stat[metric.key])}</small>`}</td>`
      }).join('')}</tr>`
    })).join('')
    const name = `${label(testId)} · ${segments[0]!.source.name}`
    return `<section class="splice-statistics"><h2>${cell(name)}</h2><table><thead><tr><th colspan="5">${cell(name)}</th></tr><tr><th>电池号</th><th>原循环号</th><th>拼接循环号</th><th>最终电压1 (V)</th><th>能量效率 (%)</th></tr></thead><tbody>${rows || '<tr><td colspan="5">无已保存循环</td></tr>'}</tbody></table></section>`
  }).join('')
  const cycles = [...new Set(record.segments.flatMap(segment => segment.originalCycleNos.map(no => segment.offset + no)))].sort((a, b) => a - b)
  const charts: string[] = []
  // 长分段按实际统计点分图，多电池按四条分组；不补缺失循环，所有分组均保留来源标识。
  for (let start = 0; start < cycles.length; start += 40) {
    const range = cycles.slice(start, start + 40)
    for (let batteryStart = 0; batteryStart < batteries.length; batteryStart += 4) {
      const group = batteries.slice(batteryStart, batteryStart + 4)
      const segments = record.segments.filter(segment => group.includes(segment.source.batteryNo) && segment.originalCycleNos.some(no => range.includes(segment.offset + no)))
      const boundaries = sources.flatMap(testId => {
        // 各电池可能缺少段首循环，来源线取本图参与电池的最早循环，跨图时限定在图内。
        const starts = segments.filter(segment => segment.source.selection.testId === testId)
          .map(segment => segment.offset + segment.originalCycleNos[0]!)
        return starts.length ? [{ name: label(testId), xAxis: Math.max(range[0]!, Math.min(...starts)) }] : []
      })
      const legend = group.map(battery => `<span><i style="background:${color(battery)}"></i>${cell(battery)}</span>`).join('')
      const sourceLegend = [...new Set(segments.map(segment => `${label(segment.source.selection.testId)} · ${segment.source.name}`))].map(name => `<span>${cell(name)}</span>`).join('')
      for (const metric of visibleMetrics) {
        const chart = init(null, undefined, { renderer: 'svg', ssr: true, width: 900, height: 300 })
        let svg: string
        try {
          chart.setOption({ animation: false, grid: { top: 42, right: 28, bottom: 45, left: 72 },
            xAxis: { type: 'value', min: range[0]! - 0.5, max: range.at(-1)! + 0.5, minInterval: 1, name: '拼接循环号', nameLocation: 'middle', nameGap: 28, axisLabel: { hideOverlap: true, formatter: (value: number) => Number.isInteger(value) ? String(value) : '' } },
            yAxis: { type: 'value', scale: true, name: metric.unit },
            series: group.map((battery, index) => ({ name: battery, type: 'line', connectNulls: false, showSymbol: true, symbolSize: 5, itemStyle: { color: color(battery) },
              // 人工调整仅作用于表格，曲线始终保留冻结的计算原值。
              data: segments.filter(segment => segment.source.batteryNo === battery).flatMap(segment => segment.originalCycleNos.filter(no => range.includes(segment.offset + no)).map(no => [segment.offset + no, numeric(segment.statistics[String(no)]?.[metric.key])])),
              markLine: index === 0 ? { silent: true, symbol: 'none', lineStyle: { color: '#82909b', type: 'dashed' }, label: { formatter: '{b}', position: 'end' }, data: boundaries } : undefined,
            })),
          })
          svg = chart.renderToSVGString()
        } finally { chart.dispose() }
        charts.push(`<article class="splice-chart"><h3>${metric.title} (${metric.unit}) · 拼接循环 ${range[0]}–${range.at(-1)}</h3><div class="splice-chart-plot">${svg}</div><div class="splice-legend">${legend}</div><div class="splice-legend">${sourceLegend}</div></article>`)
      }
    }
  }
  const date = (value: unknown) => escapeHtml(new Date(Number(value)).toLocaleString())
  const heading = record.id ? `<p>拼接报表 #${record.id} · 版本 V${record.versionNo}</p><p>创建人 ${cell(record.creator)} · 创建时间 ${date(record.createdAt)}</p><p>版本操作人 ${cell(record.operatorName)} · 版本时间 ${date(record.versionCreatedAt)}</p><p>修改说明 ${cell(record.changeSummary)}</p>` : '<p>未保存预览</p>'
  return `<div class="splice-snapshot"><header><h1>${cell(record.name)}</h1>${heading}</header><section><h2>来源测试顺序与循环对应</h2><table><thead><tr><th>顺序</th><th>来源测试</th><th>电池组</th><th>参与电池号</th><th>原循环号 → 拼接循环号</th></tr></thead><tbody>${sourceRows}</tbody></table></section><section><h2>报表字段</h2>${fieldRows ? `<table><thead><tr><th>电池号</th><th>字段</th><th>保存值</th></tr></thead><tbody>${fieldRows}</tbody></table>` : '<p>无已保存字段</p>'}</section><section><h2>统计图表</h2>${charts.join('') || `<p>${cycles.length ? '当前未启用统计图指标' : '无已保存循环统计'}</p>`}</section>${statistics}<section><h2>报表说明</h2><div class="splice-note">${cell(record.description)}</div></section></div>`
}

/** 新版每指标一条完整接续线；旧版仍走原快照呈现，不静默重算历史偏移。 */
function segmentReportBody(record: SavedSpliceReport, chartsOnly: boolean) {
  const segments = record.segments
  const cycles = record.cycleNos
  const savedColor = record.settings.seriesColors?.[0]
  const color = savedColor && /^#[\da-f]{6}$/i.test(savedColor) ? savedColor : '#3978f6'
  const sourceName = (index: number) => `来源${index + 1} · ${segments[index]!.source.name} · ${segments[index]!.source.group} · ${segments[index]!.source.batteryNo}`
  const charts = metrics.filter(metric => !record.settings.metrics || record.settings.metrics.includes(metric.key)).map(metric => {
    if (!cycles.length) return `<article class="splice-chart"><h3>${metric.title}</h3><p>无已保存循环统计</p></article>`
    const chart = init(null, undefined, { renderer: 'svg', ssr: true, width: 900, height: 320 })
    let svg: string
    try {
      chart.setOption({ animation: false, grid: { top: 42, right: 35, bottom: 48, left: 70 },
        xAxis: { type: 'value', min: cycles[0]! - 0.5, max: cycles.at(-1)! + 0.5, minInterval: 1, name: '拼接循环号', nameLocation: 'middle', nameGap: 30, axisLabel: { hideOverlap: true, formatter: (value: number) => Number.isInteger(value) ? String(value) : '' } },
        yAxis: { type: 'value', scale: true, name: metric.unit },
        series: [{ name: '接续曲线', type: 'line', connectNulls: false, showSymbol: true, symbolSize: 5, itemStyle: { color },
          // 人工表格值不进入计算原值曲线；缺值保留断点，全部指标共用循环偏移。
          data: record.settings.hiddenSeries ? [] : segments.flatMap((segment, index) => segment.originalCycleNos.map(no => ({ name: `${sourceName(index)} · 原循环${no} · 拼接循环${no + segment.offset}`, value: [no + segment.offset, numeric(segment.statistics[String(no)]?.[metric.key])] }))),
          markLine: { silent: true, symbol: 'none', lineStyle: { color: '#82909b', type: 'dashed' }, label: { show: false }, data: segments.flatMap((segment, index) => segment.originalCycleNos.length ? [{ name: `来源${index + 1}`, xAxis: segment.originalCycleNos[0]! + segment.offset }] : []) },
        }],
      })
      svg = chart.renderToSVGString()
    } finally { chart.dispose() }
    return `<article class="splice-chart" data-series-count="1"><h3>${metric.title} (${metric.unit})</h3><div class="splice-chart-plot">${svg}</div><div class="splice-legend"><span><i style="background:${color}"></i>接续曲线${record.settings.hiddenSeries ? '（已隐藏）' : ''}</span></div><div class="splice-legend">${segments.map((segment, index) => `<span>${cell(sourceName(index))} · ${segment.originalCycleNos.length ? `循环${segment.originalCycleNos[0]! + segment.offset}～${segment.originalCycleNos.at(-1)! + segment.offset}` : '无已保存循环'}</span>`).join('')}</div></article>`
  }).join('')
  if (chartsOnly) return `<div class="splice-snapshot">${charts}</div>`
  const fields = spliceFields(record.settings)
  const headers = segments.map((_, index) => `<th>${cell(sourceName(index))}</th>`).join('')
  const overrides = record.settings.sourceDetailOverrides
  const sourceDetails = overrides === undefined ? '' : `<section class="source-detail-section"><h2>来源测试详情</h2><table><thead><tr><th>字段</th>${headers}</tr></thead><tbody><tr><td>实验</td>${segments.map(segment => `<td>${escapeHtml(spliceDetailValue(segment, overrides))}</td>`).join('')}</tr>${spliceSourceFields(segments, overrides).map(field => `<tr><td>${cell(field.name)}（${field.category === 'battery' ? '电池字段' : '特殊字段'}）</td>${segments.map(segment => `<td>${escapeHtml(spliceDetailValue(segment, overrides, field))}</td>`).join('')}</tr>`).join('')}</tbody></table></section>`
  // 无独立详情设置的旧版仍使用其原字段结构，不猜补来源字段或改变历史行含义。
  const legacyExperiment = overrides === undefined ? `<tr><td>实验</td>${segments.map(segment => `<td>${escapeHtml(spliceExperiment(segment, record.settings))}</td>`).join('')}</tr>` : ''
  const details = `${sourceDetails}<section class="report-field-section"><h2>${overrides === undefined ? '测试详情' : '报表字段'}</h2><table><thead><tr><th>字段</th>${headers}</tr></thead><tbody>${legacyExperiment}${fields.map(field => `<tr><td>${cell(field.displayName)}${field.unit ? ` (${cell(field.unit)})` : ''}</td>${segments.map(segment => `<td>${escapeHtml(spliceSourceValue(segment, record.settings, field))}</td>`).join('')}</tr>`).join('')}</tbody></table></section>`
  const sources = `<section><h2>来源顺序与循环对应</h2><table><thead><tr><th>来源</th><th>原循环号 → 拼接循环号</th></tr></thead><tbody>${segments.map((segment, index) => `<tr><td>${cell(sourceName(index))}</td><td>${segment.originalCycleNos.map(no => `${no} → ${no + segment.offset}`).join('、') || '无已保存循环'}</td></tr>`).join('')}</tbody></table></section>`
  const statistics = segments.map((segment, index) => `<section class="splice-statistics"><h2>${cell(sourceName(index))}</h2><table><thead><tr><th>原循环号</th><th>拼接循环号</th>${metrics.map(metric => `<th>${metric.title} (${metric.unit})</th>`).join('')}</tr></thead><tbody>${segment.originalCycleNos.map(no => `<tr><td>${no}</td><td>${no + segment.offset}</td>${metrics.map(metric => {
    const original = segment.statistics[String(no)]?.[metric.key]
    const override = record.settings.statisticValues?.[spliceStatisticKey(segment, no, metric.key)]
    return `<td>${override === undefined ? display(original) : `${escapeHtml(override)}<br><small>计算原值：${display(original)}</small>`}</td>`
  }).join('')}</tr>`).join('') || '<tr><td colspan="4">无已保存循环</td></tr>'}</tbody></table></section>`).join('')
  return `<div class="splice-snapshot"><header><h1>${cell(record.name)}</h1><p>拼接报表 #${record.id} · 版本 V${record.versionNo}</p><p>创建人 ${cell(record.creator)} · 版本操作人 ${cell(record.operatorName)}</p><p>修改说明 ${cell(record.changeSummary)}</p></header>${sources}${details}<section><h2>统计图表</h2>${charts || '<p>当前未启用统计图指标</p>'}</section>${statistics}<section><h2>报表说明</h2><div class="splice-note">${cell(record.description)}</div></section></div>`
}

/** 先打开窗口，再使用独立导出权限读取指定版本；页面草稿不进入打印内容。 */
export function openSpliceSavedReportPrint(id: number, versionNo: number) {
  return openSavedReportPrint(() => getSplicePrintVersion(id, versionNo), record => `<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><title>${escapeHtml(record.name)} - V${record.versionNo}</title><style>@page{size:A4 landscape;margin:10mm}body{margin:0;padding:16px;background:white}@media print{body{padding:0}}${css}</style></head><body>${spliceSavedReportBody(record)}</body></html>`)
}
