# Export Mag2Car guide Markdown to PDF (requires Chrome or Edge)
param(
    [string]$InputMd = "$PSScriptRoot\Mag2Car使用指南.md",
    [string]$OutputPdf = "$PSScriptRoot\Mag2Car使用指南.pdf"
)

$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

function Escape-Html([string]$text) {
    return [System.Net.WebUtility]::HtmlEncode($text)
}

function Convert-MarkdownToHtml([string]$markdown) {
    $lines = $markdown -split "`r?`n"
    $sb = New-Object System.Text.StringBuilder
    $inCode = $false
    $inTable = $false
    $tableRows = New-Object System.Collections.Generic.List[string[]]
    $inList = $false
    $listOrdered = $false

    function Flush-Table {
        param($builder, [ref]$inTableRef, $rows)
        if (-not $inTableRef.Value) { return }
        [void]$builder.AppendLine('<table>')
        for ($i = 0; $i -lt $rows.Count; $i++) {
            $cells = $rows[$i]
            $tag = if ($i -eq 0) { 'th' } else { 'td' }
            if ($i -eq 0) { [void]$builder.AppendLine('<thead><tr>') } elseif ($i -eq 1) { [void]$builder.AppendLine('<tbody><tr>') } else { [void]$builder.AppendLine('<tr>') }
            foreach ($cell in $cells) {
                $cellHtml = Escape-Html($cell.Trim())
                $cellHtml = $cellHtml -replace '`([^`]+)`', '<code>$1</code>'
                [void]$builder.AppendLine("<$tag>$cellHtml</$tag>")
            }
            [void]$builder.AppendLine('</tr>')
            if ($i -eq 0) { [void]$builder.AppendLine('</thead>') }
        }
        if ($rows.Count -gt 1) { [void]$builder.AppendLine('</tbody>') }
        [void]$builder.AppendLine('</table>')
        $rows.Clear()
        $inTableRef.Value = $false
    }

    function Close-List {
        param($builder, [ref]$inListRef, [ref]$orderedRef)
        if (-not $inListRef.Value) { return }
        if ($orderedRef.Value) { [void]$builder.AppendLine('</ol>') } else { [void]$builder.AppendLine('</ul>') }
        $inListRef.Value = $false
        $orderedRef.Value = $false
    }

    foreach ($line in $lines) {
        if ($line -match '^\s*```') {
            if ($inCode) {
                [void]$sb.AppendLine('</code></pre>')
                $inCode = $false
            } else {
                Flush-Table $sb ([ref]$inTable) $tableRows
                Close-List $sb ([ref]$inList) ([ref]$listOrdered)
                [void]$sb.AppendLine('<pre><code>')
                $inCode = $true
            }
            continue
        }

        if ($inCode) {
            [void]$sb.AppendLine((Escape-Html $line))
            continue
        }

        if ($line -match '^\s*\|(.+)\|\s*$') {
            Close-List $sb ([ref]$inList) ([ref]$listOrdered)
            if ($line -match '^\s*\|[-:\s|]+\|\s*$') { continue }
            $cells = ($line.Trim('|') -split '\|') | ForEach-Object { $_.Trim() }
            $tableRows.Add($cells)
            $inTable = $true
            continue
        } else {
            Flush-Table $sb ([ref]$inTable) $tableRows
        }

        if ($line -match '^(#{1,6})\s+(.+)$') {
            Close-List $sb ([ref]$inList) ([ref]$listOrdered)
            $level = $Matches[1].Length
            $text = $Matches[2]
            [void]$sb.AppendLine("<h$level>$(Escape-Html $text)</h$level>")
            continue
        }

        if ($line -match '^>\s*(.+)$') {
            Close-List $sb ([ref]$inList) ([ref]$listOrdered)
            $text = $Matches[1]
            [void]$sb.AppendLine("<blockquote><p>$(Escape-Html $text)</p></blockquote>")
            continue
        }

        if ($line -match '^---\s*$') {
            Close-List $sb ([ref]$inList) ([ref]$listOrdered)
            [void]$sb.AppendLine('<hr/>')
            continue
        }

        if ($line -match '^\d+\.\s+(.+)$') {
            if (-not $inList) { [void]$sb.AppendLine('<ol>'); $inList = $true; $listOrdered = $true }
            $text = Escape-Html $Matches[1]
            $text = $text -replace '`([^`]+)`', '<code>$1</code>'
            [void]$sb.AppendLine("<li>$text</li>")
            continue
        }

        if ($line -match '^-\s+(.+)$') {
            if (-not $inList) { [void]$sb.AppendLine('<ul>'); $inList = $true; $listOrdered = $false }
            $text = Escape-Html $Matches[1]
            $text = $text -replace '`([^`]+)`', '<code>$1</code>'
            [void]$sb.AppendLine("<li>$text</li>")
            continue
        }

        if ([string]::IsNullOrWhiteSpace($line)) {
            Close-List $sb ([ref]$inList) ([ref]$listOrdered)
            continue
        }

        Close-List $sb ([ref]$inList) ([ref]$listOrdered)
        $p = Escape-Html $line
        $p = $p -replace '`([^`]+)`', '<code>$1</code>'
        [void]$sb.AppendLine("<p>$p</p>")
    }

    Flush-Table $sb ([ref]$inTable) $tableRows
    Close-List $sb ([ref]$inList) ([ref]$listOrdered)
    if ($inCode) { [void]$sb.AppendLine('</code></pre>') }
    return $sb.ToString()
}

if (-not (Test-Path $InputMd)) {
    throw "Markdown file not found: $InputMd"
}

$md = Get-Content -Path $InputMd -Raw -Encoding UTF8
$body = Convert-MarkdownToHtml $md
$htmlPath = [System.IO.Path]::ChangeExtension($OutputPdf, '.html')

$html = @"
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>Mag2Car Guide</title>
<style>
  @page { size: A4; margin: 18mm 16mm; }
  body { font-family: "Microsoft YaHei", "Segoe UI", sans-serif; color: #222; line-height: 1.55; font-size: 11pt; }
  h1 { font-size: 22pt; border-bottom: 2px solid #2563eb; padding-bottom: 8px; margin-top: 0; }
  h2 { font-size: 16pt; color: #1e40af; margin-top: 22px; page-break-after: avoid; }
  h3 { font-size: 13pt; color: #1d4ed8; margin-top: 16px; page-break-after: avoid; }
  h4, h5 { font-size: 11.5pt; margin-top: 12px; page-break-after: avoid; }
  p, li { orphans: 3; widows: 3; }
  code, pre { font-family: Consolas, "Courier New", monospace; }
  code { background: #f3f4f6; padding: 1px 4px; border-radius: 3px; font-size: 10pt; }
  pre { background: #f8fafc; border: 1px solid #e5e7eb; padding: 10px; overflow-x: auto; font-size: 9.5pt; }
  pre code { background: transparent; padding: 0; }
  table { border-collapse: collapse; width: 100%; margin: 10px 0 14px; font-size: 10pt; page-break-inside: avoid; }
  th, td { border: 1px solid #d1d5db; padding: 6px 8px; vertical-align: top; }
  th { background: #eff6ff; text-align: left; }
  tr:nth-child(even) td { background: #fafafa; }
  blockquote { border-left: 4px solid #93c5fd; margin: 10px 0; padding: 6px 12px; color: #374151; background: #f8fafc; }
  hr { border: none; border-top: 1px solid #e5e7eb; margin: 18px 0; }
  ul, ol { margin: 6px 0 10px 20px; }
</style>
</head>
<body>
$body
</body>
</html>
"@

[System.IO.File]::WriteAllText($htmlPath, $html, [System.Text.UTF8Encoding]::new($false))

$browserCandidates = @(
    "$env:ProgramFiles\Google\Chrome\Application\chrome.exe",
    "${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
    "${env:ProgramFiles(x86)}\Microsoft\Edge\Application\msedge.exe",
    "$env:ProgramFiles\Microsoft\Edge\Application\msedge.exe"
)
$browser = $browserCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $browser) {
    throw "Chrome/Edge not found. HTML generated at: $htmlPath"
}

if (Test-Path $OutputPdf) { Remove-Item $OutputPdf -Force }

$resolvedHtml = (Resolve-Path -LiteralPath $htmlPath).Path
$fileUri = [System.Uri]::new($resolvedHtml).AbsoluteUri
$args = @(
    "--headless=new",
    "--disable-gpu",
    "--no-pdf-header-footer",
    "--print-to-pdf=$OutputPdf",
    $fileUri
)
$proc = Start-Process -FilePath $browser -ArgumentList $args -Wait -PassThru

if ($proc.ExitCode -ne 0 -or -not (Test-Path $OutputPdf)) {
    throw "PDF export failed with exit code $($proc.ExitCode). HTML: $htmlPath"
}

Write-Output "PDF: $OutputPdf"
Write-Output "HTML: $htmlPath"
