$ErrorActionPreference = "Stop"

function Set-CellFormula {
    param($Shape, [string]$CellName, [string]$Formula)
    try {
        $Shape.CellsU($CellName).FormulaU = $Formula
    } catch {
    }
}

function Set-Page {
    param($Page, [string]$Name)
    $Page.Name = $Name
    $Page.NameU = $Name
    Set-CellFormula $Page.PageSheet "PageWidth" "13 in"
    Set-CellFormula $Page.PageSheet "PageHeight" "8.5 in"
}

function Add-TextBox {
    param($Page, [string]$Text, [double]$X, [double]$Y, [double]$W, [double]$H, [int]$Size = 9, [string]$Color = "RGB(0,0,0)")
    $s = $Page.DrawRectangle($X - $W / 2, $Y - $H / 2, $X + $W / 2, $Y + $H / 2)
    $s.Text = $Text
    Set-CellFormula $s "LinePattern" "0"
    Set-CellFormula $s "FillPattern" "0"
    Set-CellFormula $s "Char.Size" "$Size pt"
    Set-CellFormula $s "Char.Color" $Color
    Set-CellFormula $s "Para.HorzAlign" "1"
    Set-CellFormula $s "VerticalAlign" "1"
    return $s
}

function Add-Node {
    param(
        $Page,
        [string]$Text,
        [double]$X,
        [double]$Y,
        [double]$W = 2.35,
        [double]$H = 0.62,
        [string]$Fill = "RGB(221,235,247)",
        [string]$Line = "RGB(91,155,213)"
    )
    $s = $Page.DrawRectangle($X - $W / 2, $Y - $H / 2, $X + $W / 2, $Y + $H / 2)
    $s.Text = $Text
    Set-CellFormula $s "FillForegnd" $Fill
    Set-CellFormula $s "LineColor" $Line
    Set-CellFormula $s "LineWeight" "1.25 pt"
    Set-CellFormula $s "Char.Size" "8.5 pt"
    Set-CellFormula $s "Para.HorzAlign" "1"
    Set-CellFormula $s "VerticalAlign" "1"
    return $s
}

function Add-Arrow {
    param($Page, [double]$X1, [double]$Y1, [double]$X2, [double]$Y2, [string]$Label = "")
    $l = $Page.DrawLine($X1, $Y1, $X2, $Y2)
    Set-CellFormula $l "LineColor" "RGB(89,89,89)"
    Set-CellFormula $l "LineWeight" "1.1 pt"
    Set-CellFormula $l "EndArrow" "4"
    if ($Label -ne "") {
        Add-TextBox $Page $Label (($X1 + $X2) / 2) (($Y1 + $Y2) / 2 + 0.16) 1.35 0.26 7 "RGB(89,89,89)" | Out-Null
    }
    return $l
}

function Add-Edge {
    param($Page, $From, $To, [string]$Label = "")
    $x1 = $From.CellsU("PinX").ResultIU
    $y1 = $From.CellsU("PinY").ResultIU - $From.CellsU("Height").ResultIU / 2
    $x2 = $To.CellsU("PinX").ResultIU
    $y2 = $To.CellsU("PinY").ResultIU + $To.CellsU("Height").ResultIU / 2
    Add-Arrow $Page $x1 $y1 $x2 $y2 $Label | Out-Null
}

function Add-Legend {
    param($Page)
    Add-TextBox $Page "颜色说明：蓝=输入/配置，绿=处理，黄=判断/转换，红=异常/兜底，紫=输出" 6.5 0.35 10.5 0.35 8 "RGB(89,89,89)" | Out-Null
}

function New-Page {
    param($Doc, [int]$Index, [string]$Name)
    if ($Index -eq 1) {
        $page = $Doc.Pages.Item(1)
    } else {
        $page = $Doc.Pages.Add()
    }
    Set-Page $page $Name
    Add-TextBox $page $Name 6.5 8.1 8.8 0.45 16 "RGB(31,78,121)" | Out-Null
    Add-Legend $page
    return $page
}

function Build-MainFlow {
    param($Doc)
    $p = New-Page $Doc 1 "主流程"
    $n = @{}
    $n.start = Add-Node $p "启动 pq_tool.exe" 6.5 7.25 2.2 0.58 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.arg = Add-Node $p "判断命令行参数" 6.5 6.35 2.3 0.58 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.gui = Add-Node $p "无参数：进入 Win32 GUI`nrunPqGuiApp()" 3.0 5.35 2.65 0.72
    $n.cli = Add-Node $p "有参数：命令行解析`nXML + jsondata + origin" 10.0 5.35 2.8 0.72
    $n.ledger = Add-Node $p "获取台账和 ICD/XML`npqFetchLedgerAndIcd()" 3.0 4.25 2.9 0.72 "RGB(221,235,247)" "RGB(91,155,213)"
    $n.trace = Add-Node $p "选择测点并数据追踪`n发送 set_log 消息" 3.0 3.15 2.9 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.mq = Add-Node $p "MQ 回调落盘`njsondata_*.txt / origin_*.txt" 6.5 2.25 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.parse = Add-Node $p "pqRunParser()`n生成 final_sorted.xls" 6.5 1.28 2.7 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.preview = Add-Node $p "表格预览、筛选、编辑`n必要时逆向生成 XML" 10.0 1.28 2.9 0.72 "RGB(234,209,220)" "RGB(166,77,121)"
    Add-Edge $p $n.start $n.arg
    Add-Edge $p $n.arg $n.gui "无参数"
    Add-Edge $p $n.arg $n.cli "有参数"
    Add-Edge $p $n.gui $n.ledger
    Add-Edge $p $n.ledger $n.trace
    Add-Arrow $p 4.45 3.15 5.05 2.45 "" | Out-Null
    Add-Edge $p $n.trace $n.mq
    Add-Edge $p $n.mq $n.parse
    Add-Arrow $p 10.0 4.99 7.2 1.65 "直接解析" | Out-Null
    Add-Edge $p $n.parse $n.preview
}

function Build-UiFlow {
    param($Doc)
    $p = New-Page $Doc 2 "页面交互流程"
    $n = @{}
    $n.config = Add-Node $p "配置项页`n前置 / 接口 / MQ 参数" 2.0 6.8 2.75 0.75
    $n.ledgerPage = Add-Node $p "台账列表页`nXML/json/origin/output 路径" 5.0 6.8 2.85 0.75
    $n.tree = Add-Node $p "获取台账`n进程 -> 装置 -> 测点树" 8.0 6.8 2.7 0.75 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.actions = Add-Node $p "按钮动作`n初始化 MQ / 数据追踪 / 一键解析" 11.0 6.8 2.9 0.75 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.json = Add-Node $p "JSON 详情页`nsent / data / trace 分组" 3.4 4.9 2.85 0.75
    $n.preview = Add-Node $p "表格预览页`nSheet、状态、相位、搜索过滤" 6.5 4.9 3.0 0.75
    $n.edit = Add-Node $p "双击编辑配置列`n同步 A/B/C 三相" 9.6 4.9 2.85 0.75 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.xml = Add-Node $p "XML 预览页`n搜索、导出逆向 XML" 6.5 3.0 2.9 0.75 "RGB(234,209,220)" "RGB(166,77,121)"
    Add-Edge $p $n.config $n.ledgerPage
    Add-Edge $p $n.ledgerPage $n.tree
    Add-Edge $p $n.tree $n.actions
    Add-Arrow $p 10.5 6.43 9.6 5.3 "解析/追踪后刷新" | Out-Null
    Add-Arrow $p 10.5 6.43 6.5 5.3 "生成工作簿" | Out-Null
    Add-Arrow $p 3.0 6.43 3.4 5.3 "MQ 事件" | Out-Null
    Add-Edge $p $n.preview $n.edit
    Add-Edge $p $n.edit $n.xml "逆向生成"
    Add-Arrow $p 3.4 4.52 6.5 3.38 "自动解析完成" | Out-Null
}

function Build-IcdFlow {
    param($Doc)
    $p = New-Page $Doc 3 "ICD解析流程"
    $n = @{}
    $n.xml = Add-Node $p "ICD/XML 模板文件" 2.0 7.0 2.4 0.62
    $n.load = Add-Node $p "loadValueMetas()`n递归遍历 XML" 4.8 7.0 2.55 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.ctx = Add-Node $p "继承上下文`nTopic/DataType/Item/Sequence" 7.8 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.meta = Add-Node $p "生成 ValueMeta`nname/desc/DO/DA/wiring/offset" 10.8 7.0 3.05 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.flag = Add-Node $p "标志转换`nSequence 7=star，112=delta`n%start,end%=序列模板" 4.0 5.45 3.25 0.9 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.json = Add-Node $p "jsondata 压平`nValue_V_A_MAX_V1 -> value" 7.1 5.45 3.0 0.72
    $n.merge = Add-Node $p "mergeSequences()`n连续编号 -> [start-end]" 10.2 5.45 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.sheet = Add-Node $p "按 SheetSpec 生成行`nHISDATA/RTDATA + DATA_TYPE + 接线" 5.6 3.85 3.35 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.origin = Add-Node $p "origin 路径匹配`nDO + 相位化 DA + 数组区间" 8.8 3.85 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.out = Add-Node $p "写出 final_sorted.xls`n正常/异常/缺失/未匹配" 7.2 2.3 3.05 0.75 "RGB(234,209,220)" "RGB(166,77,121)"
    $n.import = Add-Node $p "导入外部 ICD`nLN/DOI desc -> 未匹配页字段说明" 7.2 1.15 4.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)"
    Add-Edge $p $n.xml $n.load
    Add-Edge $p $n.load $n.ctx
    Add-Edge $p $n.ctx $n.meta
    Add-Arrow $p 10.0 6.64 5.0 5.85 "Value/@name" | Out-Null
    Add-Edge $p $n.json $n.merge
    Add-Arrow $p 10.2 5.09 8.8 4.28 "" | Out-Null
    Add-Arrow $p 4.0 5.00 5.6 4.28 "" | Out-Null
    Add-Edge $p $n.sheet $n.out
    Add-Edge $p $n.origin $n.out
    Add-Edge $p $n.out $n.import
}

function Build-TraceFlow {
    param($Doc)
    $p = New-Page $Doc 4 "数据追踪流程"
    $n = @{}
    $n.sel = Add-Node $p "左侧树选择测点`ndevice + monitor" 2.2 7.0 2.6 0.72
    $n.dir = Add-Node $p "pqTraceDirectoryFor()`nprocess/device/monitor 目录" 5.1 7.0 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.clean = Add-Node $p "清空旧文本记录`n准备 json/origin/output 路径" 8.2 7.0 3.1 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.payload = Add-Node $p "pqBuildTracePayload()`nguid + set_log + frontType" 11.1 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.ctx = Add-Node $p "setTraceTarget()`n写 trace_context.json" 3.6 5.45 2.9 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.send = Add-Node $p "RocketMQ 可用？" 6.5 5.45 2.35 0.62 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.mq = Add-Node $p "同步发送 TopicLOG`nTagLOG / KeyLOG" 9.3 5.45 2.65 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.outbox = Add-Node $p "不可用：写 mq_outbox_*.jsonl" 9.3 4.35 2.95 0.62 "RGB(244,204,204)" "RGB(192,0,0)"
    $n.cb = Add-Node $p "MQ 消费回调`nTopic/Tag + monitorId/guid 路由" 3.6 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.data = Add-Node $p "DATATopic`nDATA_TYPE 去重 -> jsondata_*.txt" 6.9 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.trace = Add-Node $p "TraceTopic`n时间戳过滤 -> origin_*.txt" 10.2 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.auto = Add-Node $p "PostMessage 到 GUI`nautoParseTraceDir()" 6.9 1.95 3.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)"
    Add-Edge $p $n.sel $n.dir
    Add-Edge $p $n.dir $n.clean
    Add-Edge $p $n.clean $n.payload
    Add-Arrow $p 10.2 6.64 4.5 5.85 "" | Out-Null
    Add-Edge $p $n.ctx $n.send
    Add-Edge $p $n.send $n.mq "是"
    Add-Arrow $p 6.5 5.14 8.1 4.45 "否" | Out-Null
    Add-Arrow $p 9.3 5.09 3.6 3.88 "收到消息" | Out-Null
    Add-Edge $p $n.cb $n.data
    Add-Edge $p $n.data $n.trace
    Add-Arrow $p 6.9 3.04 6.9 2.33 "文件到齐后" | Out-Null
}

function Build-ReverseXmlFlow {
    param($Doc)
    $p = New-Page $Doc 5 "逆向生成XML流程"
    $n = @{}
    $n.preview = Add-Node $p "表格预览页`n读取 final_sorted.xls" 2.0 7.0 2.75 0.72
    $n.edit = Add-Node $p "双击编辑配置列`n数组基准/偏移/DO/DA" 5.0 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.sync = Add-Node $p "commitPreviewEdit()`n同步 A/B/C 三相并置 dirty" 8.2 7.0 3.15 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.rows = Add-Node $p "collectReverseRows()`n只采集数据行和改动行" 11.1 7.0 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.spec = Add-Node $p "reverseSpecForSheet()`nSheet 名 -> Topic/DataType/wiring" 3.6 5.4 3.35 0.82 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.xml = Add-Node $p "读取原始 XML`ncollectValueNodes()" 6.9 5.4 2.9 0.72
    $n.match = Add-Node $p "reverseNodeMatches()`n优先原始 DO/DA，再 name/desc" 10.2 5.4 3.35 0.82 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.convert = Add-Node $p "标志还原`n[start-end] -> %start,end%`n[offset] -> [%offset]" 5.1 3.75 3.45 0.92 "RGB(255,242,204)" "RGB(191,143,0)"
    $n.update = Add-Node $p "更新 Value 属性`nname / DO / DA / Offset" 8.5 3.75 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)"
    $n.out = Add-Node $p "XML 预览页`n搜索 / 导出 xml 或 icd" 6.8 2.15 3.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)"
    Add-Edge $p $n.preview $n.edit
    Add-Edge $p $n.edit $n.sync
    Add-Edge $p $n.sync $n.rows
    Add-Arrow $p 10.2 6.64 4.3 5.82 "" | Out-Null
    Add-Edge $p $n.spec $n.xml
    Add-Edge $p $n.xml $n.match
    Add-Arrow $p 10.2 4.98 8.5 4.15 "匹配到节点" | Out-Null
    Add-Edge $p $n.convert $n.update
    Add-Edge $p $n.update $n.out
}

$outDir = $PSScriptRoot
$outPath = Join-Path $outDir "pq_tool_flowcharts.vsdx"

$visio = $null
$doc = $null
try {
    $visio = New-Object -ComObject Visio.Application
    $visio.Visible = $false
    $visio.AlertResponse = 7
    $doc = $visio.Documents.Add("")

    Build-MainFlow $doc
    Build-UiFlow $doc
    Build-IcdFlow $doc
    Build-TraceFlow $doc
    Build-ReverseXmlFlow $doc

    if (Test-Path -LiteralPath $outPath) {
        Remove-Item -LiteralPath $outPath -Force
    }
    $doc.SaveAs($outPath)
    Write-Host "[OK] Saved $outPath"
}
finally {
    if ($doc -ne $null) {
        try { $doc.Close() } catch {}
        [System.Runtime.InteropServices.Marshal]::ReleaseComObject($doc) | Out-Null
    }
    if ($visio -ne $null) {
        try { $visio.Quit() } catch {}
        [System.Runtime.InteropServices.Marshal]::ReleaseComObject($visio) | Out-Null
    }
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
}

