# ----------------------------------------------------------------
# Scenario 4: Multi-Repo Collaboration
# Flow: Cross-repo issue tracking -> PR status dashboard -> Coordinated release
#
# Commands chained:
#   1. repo +list      -- list all repos in org
#   2. issue +list     -- fetch open/closed issues from each repo
#   3. pr +list        -- fetch open/merged PRs from each repo
#   4. release +list   -- check latest release across repos
#   5. Generate HTML dashboard (summary cards + table + per-repo details)
#   6. release +create -- (optional) coordinated release across all repos
# ----------------------------------------------------------------
#Requires -Version 5.1

param(
    [string]$Org = "",
    [string]$Repos = "",
    [string]$Release = "",
    [string]$Output = "dashboard.html",
    [int]$DetailLimit = 10,
    [switch]$DryRun,
    [switch]$Help
)

$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot/lib/common.psm1" -Force -WarningAction SilentlyContinue

if ($Help) {
    Write-Host "Usage: powershell 04-multi-repo-collab.ps1 -Org ORG [-Repos 'repo1,repo2'] [-Release TAG] [-Output FILE] [-DetailLimit N] [-DryRun]"
    exit 0
}

if (-not $Org) { Log-Err "Org is required (use -Help for usage)"; exit 1 }

Check-Auth

# -- Helpers --
function Html-Escape([string]$s) {
    if ($null -eq $s) { return "" }
    $s = $s -replace '&', '&amp;'
    $s = $s -replace '<', '&lt;'
    $s = $s -replace '>', '&gt;'
    $s = $s -replace '"', '&quot;'
    return $s
}

# Health score (0-100) aligned with gitlink-health skill.
# Core 75 (issue efficiency / PR efficiency / activity, -25 each),
# auxiliary 25 (issue backlog -10, PR backlog -10, no recent release -5).
# releaseAge: days since latest release, -1 = none.
function Compute-Health([int]$oi, [int]$ci, [int]$op, [int]$mp, [int]$age) {
    $health = 100
    # 核心指标 (75)
    $ti = $oi + $ci
    $res = if ($ti -gt 0) { $ci / $ti } else { 1 }
    if ($res -lt 0.5) { $health -= 25 }        # Issue 处理效率 (响应慢代理)
    $tp = $op + $mp
    $mr = if ($tp -gt 0) { $mp / $tp } else { 1 }
    if ($mr -lt 0.5) { $health -= 25 }         # PR 合并效率 (合并慢代理)
    if (($mp + $ci) -eq 0) { $health -= 25 }   # 活跃度低: 无已完成工作
    # 辅助指标 (25)
    if ($oi -gt 20) { $health -= 10 }          # Issue 积压
    if ($op -gt 10) { $health -= 10 }          # PR 积压
    if ($age -lt 0 -or $age -gt 30) { $health -= 5 }  # 无近期发布
    if ($health -lt 0) { $health = 0 }
    if ($health -gt 100) { $health = 100 }
    return [int]$health
}

# Map score -> @{ Label; Class } (5 bands per gitlink-health skill)
function Get-HealthGrade([int]$score) {
    if     ($score -ge 90) { return @{ Label = "优秀"; Class = "excellent" } }
    elseif ($score -ge 70) { return @{ Label = "良好"; Class = "good" } }
    elseif ($score -ge 50) { return @{ Label = "一般"; Class = "moderate" } }
    elseif ($score -ge 30) { return @{ Label = "需关注"; Class = "attention" } }
    else                   { return @{ Label = "严重"; Class = "critical" } }
}

# -- Step 1: List Repositories --
Log-Title "多仓库协同看板 (Multi-Repo Collaboration Dashboard)"

Log-Step "获取组织 $Org 下的仓库列表..."
$reposJson = Invoke-GLCheck "repo", "+list", "--user", $Org, "--limit", "100"
if (-not $reposJson) { Log-Err "获取仓库列表失败"; exit 1 }

$allRepos = @()
$rd = $reposJson.data
if ($rd.projects) { $allRepos = @($rd.projects) }
elseif ($rd -is [array]) { $allRepos = $rd }

Log-Ok "组织下共有 $($allRepos.Count) 个仓库"

$repoList = @()
if ($Repos) {
    $repoList = $Repos -split ','
    Log-Info "仅处理指定仓库: $($repoList -join ', ')"
} else {
    foreach ($r in $allRepos) {
        $rname = if ($r.name) { $r.name } elseif ($r.identifier) { $r.identifier } else { $null }
        if ($rname) { $repoList += $rname }
    }
}

if ($repoList.Count -eq 0) { Log-Err "没有可处理的仓库。请检查 -Org 或用 -Repos 指定。"; exit 1 }
Log-Ok "将处理 $($repoList.Count) 个仓库"

# -- Step 2-4: Collect data across repos --
Log-Title "跨仓库数据采集"

$totalActivity = 0; $totalOpenIssues = 0; $totalOpenPRs = 0; $totalMergedPRs = 0; $healthSum = 0
$dashboardRows = ""
$repoDetails = ""

foreach ($repo in $repoList) {
    Divider
    Log-Step "处理 $Org/$repo..."

    # Open issues
    $issuesObj = $null; $openIssues = 0; $openIssueItems = @()
    $issuesRaw = Invoke-GL "issue", "+list", "--owner", $Org, "--repo", $repo, "--state", "open", "--limit", "50"
    if ($issuesRaw) { try {
        $issuesObj = $issuesRaw | ConvertFrom-Json
        if ($issuesObj.ok -and $issuesObj.data.issues) { $openIssueItems = @($issuesObj.data.issues); $openIssues = $openIssueItems.Count }
    } catch {} }

    # Closed issues
    $closedIssues = 0
    $closedRaw = Invoke-GL "issue", "+list", "--owner", $Org, "--repo", $repo, "--state", "closed", "--limit", "50"
    if ($closedRaw) { try {
        $closedObj = $closedRaw | ConvertFrom-Json
        if ($closedObj.ok -and $closedObj.data.issues) { $closedIssues = @($closedObj.data.issues).Count }
    } catch {} }

    # Open PRs
    $openPRs = 0; $openPRItems = @()
    $prsRaw = Invoke-GL "pr", "+list", "--owner", $Org, "--repo", $repo, "--state", "open", "--limit", "50"
    if ($prsRaw) { try {
        $prsObj = $prsRaw | ConvertFrom-Json
        if ($prsObj.ok) {
            if ($prsObj.data.issues) { $openPRItems = @($prsObj.data.issues) }
            elseif ($prsObj.data.pulls) { $openPRItems = @($prsObj.data.pulls) }
            elseif ($prsObj.data -is [array]) { $openPRItems = @($prsObj.data) }
            $openPRs = $openPRItems.Count
        }
    } catch {} }

    # Merged PRs
    $mergedPRs = 0
    $mergedRaw = Invoke-GL "pr", "+list", "--owner", $Org, "--repo", $repo, "--state", "merged", "--limit", "50"
    if ($mergedRaw) { try {
        $mergedObj = $mergedRaw | ConvertFrom-Json
        if ($mergedObj.ok) {
            if ($mergedObj.data.issues) { $mergedPRs = @($mergedObj.data.issues).Count }
            elseif ($mergedObj.data.pulls) { $mergedPRs = @($mergedObj.data.pulls).Count }
            elseif ($mergedObj.data -is [array]) { $mergedPRs = @($mergedObj.data).Count }
        }
    } catch {} }

    # Latest release + age
    $latestRelease = "none"; $releaseAge = -1
    $releaseRaw = Invoke-GL "release", "+list", "--owner", $Org, "--repo", $repo, "--limit", "1"
    if ($releaseRaw) { try {
        $releaseObj = $releaseRaw | ConvertFrom-Json
        $rels = $null
        if ($releaseObj.ok -and $releaseObj.data.releases) { $rels = @($releaseObj.data.releases) }
        elseif ($releaseObj.ok -and $releaseObj.data -is [array]) { $rels = @($releaseObj.data) }
        if ($rels -and $rels.Count -gt 0) {
            $latestRelease = if ($rels[0].tag_name) { $rels[0].tag_name } elseif ($rels[0].name) { $rels[0].name } else { "none" }
            $relDate = if ($rels[0].created_at) { $rels[0].created_at } elseif ($rels[0].created_on) { $rels[0].created_on } elseif ($rels[0].published_at) { $rels[0].published_at } else { $null }
            if ($relDate) {
                try { $releaseAge = [int]((Get-Date) - [datetime]$relDate).TotalDays } catch { $releaseAge = 0 }
            } else { $releaseAge = 0 }
        }
    } catch {} }

    $health = Compute-Health $openIssues $closedIssues $openPRs $mergedPRs $releaseAge
    $grade = Get-HealthGrade $health

    Log-Ok "$repo : Issue(开:$openIssues 闭:$closedIssues) PR(开:$openPRs 合:$mergedPRs) Release:$latestRelease 健康度:$health($($grade.Label))"

    # Open issue detail rows
    $issueRows = ""
    $limit = [Math]::Min($openIssues, $DetailLimit)
    for ($i = 0; $i -lt $limit; $i++) {
        $it = $openIssueItems[$i]
        $iid = if ($it.id) { $it.id } elseif ($it.number) { $it.number } else { "" }
        $ititle = if ($it.name) { $it.name } elseif ($it.subject) { $it.subject } elseif ($it.title) { $it.title } else { "" }
        $iauthor = if ($it.author_name) { $it.author_name } elseif ($it.author_login) { $it.author_login } elseif ($it.author.login) { $it.author.login } else { "unknown" }
        $issueRows += "<tr><td>#$(Html-Escape ([string]$iid))</td><td>$(Html-Escape ([string]$ititle))</td><td>@$(Html-Escape ([string]$iauthor))</td></tr>"
    }
    if (-not $issueRows) { $issueRows = '<tr><td colspan="3" class="empty">无未关闭 Issue</td></tr>' }

    # Open PR detail rows
    $prRows = ""
    $limit = [Math]::Min($openPRs, $DetailLimit)
    for ($i = 0; $i -lt $limit; $i++) {
        $pt = $openPRItems[$i]
        $pid = if ($pt.pull_request_number) { $pt.pull_request_number } elseif ($pt.number) { $pt.number } elseif ($pt.id) { $pt.id } else { "" }
        $ptitle = if ($pt.subject) { $pt.subject } elseif ($pt.title) { $pt.title } elseif ($pt.name) { $pt.name } else { "" }
        $pauthor = if ($pt.author_name) { $pt.author_name } elseif ($pt.author_login) { $pt.author_login } elseif ($pt.author.login) { $pt.author.login } else { "unknown" }
        $prRows += "<tr><td>#$(Html-Escape ([string]$pid))</td><td>$(Html-Escape ([string]$ptitle))</td><td>@$(Html-Escape ([string]$pauthor))</td></tr>"
    }
    if (-not $prRows) { $prRows = '<tr><td colspan="3" class="empty">无未合并 PR</td></tr>' }

    $repoDetails += @"
<details><summary><span class="badge $($grade.Class)">$health</span> $(Html-Escape $repo) — Issue 开 $openIssues / PR 开 $openPRs</summary>
  <div class="detail-grid">
    <div><h4>未关闭 Issue（最多 $DetailLimit 条）</h4>
      <table class="detail-table"><thead><tr><th>编号</th><th>标题</th><th>作者</th></tr></thead><tbody>$issueRows</tbody></table></div>
    <div><h4>未合并 PR（最多 $DetailLimit 条）</h4>
      <table class="detail-table"><thead><tr><th>编号</th><th>标题</th><th>作者</th></tr></thead><tbody>$prRows</tbody></table></div>
  </div>
</details>
"@

    $totalActivity += $openIssues + $closedIssues + $openPRs + $mergedPRs
    $totalOpenIssues += $openIssues
    $totalOpenPRs += $openPRs
    $totalMergedPRs += $mergedPRs
    $healthSum += $health

    $relDisplay = if ($latestRelease -eq "none") { "—" } else { Html-Escape $latestRelease }

    $dashboardRows += @"
<tr>
    <td><a href="https://gitlink.org.cn/$Org/$repo" target="_blank">$(Html-Escape $repo)</a></td>
    <td>$openIssues</td><td>$closedIssues</td>
    <td>$openPRs</td><td>$mergedPRs</td><td>$relDisplay</td>
    <td><span class="badge $($grade.Class)">$health</span> <span class="grade $($grade.Class)">$($grade.Label)</span></td>
</tr>
"@
}

$avgHealth = if ($repoList.Count -gt 0) { [int]($healthSum / $repoList.Count) } else { 0 }

# -- Step 5: Generate HTML Dashboard --
Log-Title "生成 HTML 看板"

$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$repoCount = $repoList.Count

$html = @"
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多仓库协同看板 - $Org</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei', sans-serif; background: #f0f2f5; padding: 24px; color: #1f2329; }
.container { max-width: 1280px; margin: 0 auto; }
h1 { color: #1f2329; margin-bottom: 6px; font-size: 26px; }
.timestamp { color: #8a919f; font-size: 13px; margin-bottom: 24px; }
.summary { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 28px; }
.card { background: #fff; border-radius: 10px; padding: 18px 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
.card h3 { color: #8a919f; font-size: 13px; margin-bottom: 8px; font-weight: 500; }
.card .value { font-size: 30px; font-weight: 700; }
.card.blue .value { color: #2f80ed; }
.card.orange .value { color: #f2994a; }
.card.purple .value { color: #9b51e0; }
.card.green .value { color: #27ae60; }
.card.teal .value { color: #17a2b8; }
h2 { font-size: 18px; margin: 24px 0 14px; color: #1f2329; }
table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 10px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
th { background: #2f80ed; color: #fff; padding: 12px 16px; text-align: left; font-weight: 500; font-size: 14px; }
td { padding: 11px 16px; border-bottom: 1px solid #eef0f3; font-size: 14px; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: #f7f9fc; }
a { color: #2f80ed; text-decoration: none; font-weight: 500; }
a:hover { text-decoration: underline; }
.badge { display: inline-block; min-width: 34px; text-align: center; padding: 2px 8px; border-radius: 12px; color: #fff; font-weight: 700; font-size: 13px; }
.grade { font-size: 13px; margin-left: 4px; }
.badge.excellent { background: #27ae60; } .grade.excellent { color: #27ae60; }
.badge.good { background: #2f80ed; } .grade.good { color: #2f80ed; }
.badge.moderate { background: #f2c94c; } .grade.moderate { color: #d9a400; }
.badge.attention { background: #f2994a; } .grade.attention { color: #f2994a; }
.badge.critical { background: #eb5757; } .grade.critical { color: #eb5757; }
details { background: #fff; border-radius: 10px; margin-bottom: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); overflow: hidden; }
summary { padding: 14px 18px; cursor: pointer; font-weight: 600; font-size: 15px; user-select: none; }
summary:hover { background: #f7f9fc; }
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; padding: 0 18px 18px; }
.detail-table th { background: #eef2f8; color: #4a5568; padding: 8px 12px; font-size: 13px; }
.detail-table td { padding: 8px 12px; font-size: 13px; }
.detail-grid h4 { font-size: 14px; margin-bottom: 8px; color: #4a5568; }
.empty { color: #b0b7c3; text-align: center; font-style: italic; }
@media (max-width: 900px) { .summary { grid-template-columns: repeat(2, 1fr); } .detail-grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="container">
<h1>多仓库协同看板</h1>
<p class="timestamp">生成时间：$timestamp ｜ 组织：$Org</p>
<div class="summary">
    <div class="card blue"><h3>仓库总数</h3><div class="value">$repoCount</div></div>
    <div class="card orange"><h3>未关闭 Issue</h3><div class="value">$totalOpenIssues</div></div>
    <div class="card purple"><h3>未合并 PR</h3><div class="value">$totalOpenPRs</div></div>
    <div class="card green"><h3>已合并 PR</h3><div class="value">$totalMergedPRs</div></div>
    <div class="card teal"><h3>平均健康度</h3><div class="value">$avgHealth</div></div>
</div>

<h2>仓库概览</h2>
<table>
<thead><tr><th>仓库</th><th>未关闭 Issue</th><th>已关闭 Issue</th><th>未合并 PR</th><th>已合并 PR</th><th>最新 Release</th><th>健康度</th></tr></thead>
<tbody>
$dashboardRows
</tbody>
</table>

<h2>仓库详情</h2>
$repoDetails
</div>
</body>
</html>
"@

$utf8 = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText((Join-Path (Get-Location) $Output), $html, $utf8)
Log-Ok "看板已保存: $Output"

# -- Step 6: Coordinated Release --
if ($Release) {
    Log-Title "协调发版: $Release"

    if ($DryRun) {
        Log-Warn "[DRY RUN] 将为以下 $($repoList.Count) 个仓库创建 Release ${Release}:"
        foreach ($repo in $repoList) { Log-Warn "  [DRY RUN] $Org/$repo -> $Release" }
    } else {
        $relOk = 0; $relFail = 0
        foreach ($repo in $repoList) {
            Log-Step "为 $Org/$repo 创建 Release..."
            $relBody = "Coordinated release $Release for $Org/$repo"
            $relResult = Invoke-GL "release", "+create", "--owner", $Org, "--repo", $repo, "--tag", $Release, "--name", "Release $Release", "--body", $relBody
            $ok = $false
            if ($relResult) { try { $ok = ($relResult | ConvertFrom-Json).ok } catch { $ok = $false } }
            if ($ok) { Log-Ok "Release $Release 已在 $repo 创建"; $relOk++ }
            else { Log-Warn "Release 创建失败: $repo (tag 可能已存在)"; $relFail++ }
        }
        Log-Info "协调发版结果: 成功 $relOk / 失败 $relFail"
    }
}

# ----------------------------------------------------------------
Log-Title "多仓库看板完成"
# ----------------------------------------------------------------

Write-Host "  处理仓库:     $repoCount" -ForegroundColor Green
Write-Host "  未关闭 Issue: $totalOpenIssues" -ForegroundColor Green
Write-Host "  未合并 PR:    $totalOpenPRs" -ForegroundColor Green
Write-Host "  已合并 PR:    $totalMergedPRs" -ForegroundColor Green
Write-Host "  平均健康度:   $avgHealth / 100" -ForegroundColor Green
Write-Host "  看板文件:     $Output" -ForegroundColor Green
if ($Release) {
    $suffix = if ($DryRun) { " (dry-run)" } else { "" }
    Write-Host "  协调发版:     $Release$suffix" -ForegroundColor Green
}
Write-Host ""
Write-Host "打开看板:" -ForegroundColor Cyan
Write-Host "  Start-Process $Output"
