# ----------------------------------------------------------------
# Scenario 1: Community Operations Automation (定时批量链路)
# Flow: 收集周期数据 → 10类关键词分类 → 生成 Release Notes + 社区周报
# 遵循 gitlink-changelog skill 的收集→分类→发布流程
# 条目格式: - 描述 (#编号) (@作者) [分类]

# ----------------------------------------------------------------
#Requires -Version 5.1

param(
    [string]$Owner = "",
    [string]$Repo = "",
    [int]$PeriodHours = 6,
    [string]$ReleaseVersion = "",
    [switch]$DryRun,
    [switch]$Help
)

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

if ($Help) {
    Write-Host "Usage: powershell 01-community-ops.ps1 [-Owner O] [-Repo R] [-PeriodHours N] [-ReleaseVersion TAG] [-DryRun]"
    exit 0
}

Check-Auth
$r = Resolve-OwnerRepo $Owner $Repo
$Owner = $r.Owner; $Repo = $r.Repo

# ================================================================
# Phase 1: 时间窗口和基线
# ================================================================
Log-Title "Phase 1: Time Window"


$periodStart = (Get-Date).AddHours(-$PeriodHours)
$periodEnd = Get-Date
$periodStartStr = $periodStart.ToString("yyyy-MM-dd HH:mm")
$periodEndStr = $periodEnd.ToString("yyyy-MM-dd HH:mm")


Log-Step "Finding previous release..."
$prevTag = ""
$releasesJson = Invoke-GL release,+list,--owner,$Owner,--repo,$Repo,--limit,5
if ($releasesJson) {
    try {
        $relData = ($releasesJson | ConvertFrom-Json).data
        $releases = if ($relData.releases) { @($relData.releases) } elseif ($relData -is [array]) { @($relData) } else { @() }
        if ($releases.Count -gt 0) {
            $prevTag = if ($releases[0].tag_name) { $releases[0].tag_name } else { "" }

        }
    } catch {}
}
if (-not $prevTag) { $prevTag = "initial" }

$newVersion = if ($ReleaseVersion) { $ReleaseVersion } else { "weekly-$(Get-Date -Format 'yyyyMMdd')" }
Log-Ok "Period: $periodStartStr ~ $periodEndStr"
Log-Ok "Release: $prevTag -> $newVersion"

# ================================================================
# Phase 2: 收集数据
# ================================================================
Log-Title "Phase 2: Collect Data"

# -- Commits --
Log-Step "Collecting commits..."
$commitCount = 0
$commitList = "(无 commit 数据)"
if ($prevTag -ne "initial") {
    $compareJson = Invoke-GL api,GET,"/v1/$Owner/$Repo/compare/$prevTag...master"
    if ($compareJson) {
        try {
            $cData = ($compareJson | ConvertFrom-Json).data
            if ($cData.commits) {
                $commits = @($cData.commits)
                $commitCount = $commits.Count
                $lines = @()
                $show = [Math]::Min($commitCount, 50)
                for ($i = 0; $i -lt $show; $i++) {
                    $msg = if ($commits[$i].commit.message) { ($commits[$i].commit.message -split "`n")[0] } else { "N/A" }
                    $author = if ($commits[$i].commit.author.name) { $commits[$i].commit.author.name } else { "unknown" }
                    $lines += "- $msg ($author)"
                }
                $commitList = $lines -join "`n"
            }
        } catch {}

    }
}
Log-Ok "Commits: $commitCount"

# -- Merged PRs --
Log-Step "Collecting merged PRs..."
$prItems = @()
$prContributors = @{}
$prsJson = Invoke-GL pr,+list,--owner,$Owner,--repo,$Repo,--state,merged,--limit,100
if ($prsJson) {
    try {
        $prData = ($prsJson | ConvertFrom-Json).data
        $prs = if ($prData.issues) { @($prData.issues) } elseif ($prData.pulls) { @($prData.pulls) } elseif ($prData -is [array]) { @($prData) } else { @() }
        foreach ($pr in $prs) {
            $prTitle = if ($pr.name) { $pr.name } elseif ($pr.subject) { $pr.subject } elseif ($pr.title) { $pr.title } else { "N/A" }
            $prNum = if ($pr.pull_request_number) { $pr.pull_request_number } elseif ($pr.number) { $pr.number } else { "?" }
            $prAuthor = if ($pr.author_login) { $pr.author_login } elseif ($pr.author.login) { $pr.author.login } else { "?" }
            $prItems += "- $prTitle (#$prNum) (@$prAuthor)"
            $prContributors[$prAuthor] = $true

        }
    } catch {}
}
$prCount = $prItems.Count
$prText = if ($prCount -gt 0) { ($prItems -join "`n") } else { "(本周期无 PR 合并)" }
Log-Ok "Merged PRs: $prCount"

# -- Issues (新增 + 关闭) --
Log-Step "Collecting issues..."
$bugLines = @()
$featLines = @()
$docLines = @()
$otherLines = @()
$issContributors = @{}
$issCount = 0
# Dedupe by issue index: the same issue can be returned by both the open
# and closed state queries, which would otherwise double-count it.
$seenIssues = @{}
$today = (Get-Date -Format "yyyy-MM-dd")
$yesterday = ((Get-Date).AddDays(-1)).ToString("yyyy-MM-dd")

foreach ($state in @("open","closed")) {
    $issJson = Invoke-GL issue,+list,--owner,$Owner,--repo,$Repo,--state,$state,--limit,100
    if (-not $issJson) { continue }
    try {
        $issData = ($issJson | ConvertFrom-Json).data
        $issues = if ($issData.issues) { @($issData.issues) } elseif ($issData -is [array]) { @($issData) } else { @() }
        foreach ($iss in $issues) {
            $num = if ($iss.project_issues_index) { $iss.project_issues_index } elseif ($iss.number) { $iss.number } else { "?" }
            if ($num -ne "?" -and $seenIssues.ContainsKey($num)) { continue }
            if ($num -ne "?") { $seenIssues[$num] = $true }
            $title = if ($iss.subject) { $iss.subject } elseif ($iss.title) { $iss.title } else { "N/A" }
            $desc = if ($iss.description) { $iss.description } else { "" }
            $author = if ($iss.author.login) { $iss.author.login } elseif ($iss.author.username) { $iss.author.username } else { "?" }
            $created = if ($iss.created_at) { $iss.created_at } else { "" }
            $closed = if ($iss.closed_at) { $iss.closed_at } else { "" }
            $stateName = if ($iss.status.name) { $iss.status.name } elseif ($iss.state) { $iss.state } else { "?" }

            # 时间筛选：created 或 closed >= periodStart
            $inPeriod = $false
            if ($created) { try { if (([DateTime]$created) -ge $periodStart) { $inPeriod = $true } } catch {} }
            if (-not $inPeriod -and $closed) { try { if (([DateTime]$closed) -ge $periodStart) { $inPeriod = $true } } catch {} }
            if (-not $inPeriod) { continue }

            $line = "- $title (#$num) (@$author)"
            if ($stateName -match "关闭|closed") { $line += " [已关闭]" }

            # 标题+描述 关键词分类 (10 个标准类别)
            $combined = "$title $desc".ToLower()
            if ($combined -match '(?i)bug|error|crash|fault|fix|缺陷|错误|异常|崩溃|修复|故障') {
                $line += " [缺陷]"; $bugLines += $line
            } elseif ($combined -match '(?i)feature|enhancement|add|新增|建议|功能|特性|新功能|支持|request') {
                $line += " [功能]"; $featLines += $line
            } elseif ($combined -match '(?i)doc|readme|guide|wiki|tutorial|文档|说明|教程|手册') {
                $line += " [文档]"; $docLines += $line
            } elseif ($combined -match '(?i)test|测试|用例|覆盖|验证') {
                $line += " [测试]"; $docLines += $line
            } elseif ($combined -match '(?i)duplicate|重复|重复的') {
                $line += " [重复]"; $docLines += $line
            } elseif ($combined -match '(?i)question|疑问|不确定|讨论|澄清|是否|可否') {
                $line += " [疑问]"; $docLines += $line
            } elseif ($combined -match '(?i)help|协助|帮助|协作|请求帮助|互助') {
                $line += " [协助]"; $docLines += $line
            } elseif ($combined -match '(?i)postpone|wontfix|暂缓|搁置|低优|不重要|不紧急|暂不|delay') {
                $line += " [搁置]"; $docLines += $line
            } elseif ($combined -match '(?i)task|todo|任务|待办|计划|安排') {
                $line += " [任务]"; $docLines += $line
            } elseif ($combined -match '(?i)support|兼容|环境|依赖|平台|适配') {
                $line += " [支持]"; $docLines += $line
            } else {
                $line += " [其他]"; $otherLines += $line
            }

            if ($author -ne "?") { $issContributors[$author] = $true }
            $issCount++
        }
    } catch {}
}
$bugSection = if ($bugLines.Count -gt 0) { ($bugLines -join "`n") } else { "_无_" }
$featSection = if ($featLines.Count -gt 0) { ($featLines -join "`n") } else { "_无_" }
$docSection = if ($docLines.Count -gt 0) { ($docLines -join "`n") } else { "_无_" }
$otherSection = if ($otherLines.Count -gt 0) { ($otherLines -join "`n") } else { "_无_" }
Log-Ok "Issues in period: $issCount"

# -- 动态收集标签 ID 映射 (与 01a-issue-triage.ps1 一致) --
Log-Step "Discovering label IDs..."
$tagIdMap = @{}

# 优先从项目 issue_tags API 获取
$tagsApi = Invoke-GL api,GET,"/v1/$Owner/$Repo/issue_tags"
if ($tagsApi) {
    try {
        $tData = ($tagsApi | ConvertFrom-Json).data
        $tagList = if ($tData.issue_tags) { @($tData.issue_tags) } elseif ($tData -is [array]) { @($tData) } else { @() }
        foreach ($t in $tagList) {
            if ($t.id -and $t.name) { $tagIdMap[$t.name] = $t.id }
        }
    } catch {}
}

# 补充：从已有 issue 的 tags 字段收集
foreach ($state in @("open","closed")) {
    $sample = Invoke-GL issue,+list,--owner,$Owner,--repo,$Repo,--state,$state,--limit,50
    if ($sample) {
        try {
            $sData = ($sample | ConvertFrom-Json).data
            $sIssues = if ($sData.issues) { @($sData.issues) } elseif ($sData -is [array]) { @($sData) } else { @() }
            foreach ($iss in $sIssues) {
                if ($iss.tags) {
                    foreach ($t in $iss.tags) {
                        if ($t.id -and $t.name) { $tagIdMap[$t.name] = $t.id }
                    }
                }
            }
        } catch {}
    }
}
$tagFound = @()
foreach ($k in $tagIdMap.Keys) { $tagFound += "$k($($tagIdMap[$k]))" }
if ($tagFound.Count -gt 0) { Log-Ok "Found tags: $($tagFound -join ' ')" } else { Log-Warn "No tags found in repo" }

# -- 打标签 & 分配责任人 (自动分类后的实际写入) --
# 收集需要处理的 Issue 信息 (编号, issue ID, 标签名, 作者)
$triageItems = @()
$seenTriage = @{}

foreach ($state in @("open","closed")) {
    $issJson2 = Invoke-GL issue,+list,--owner,$Owner,--repo,$Repo,--state,$state,--limit,100
    if (-not $issJson2) { continue }
    try {
        $issData2 = ($issJson2 | ConvertFrom-Json).data
        $issues2 = if ($issData2.issues) { @($issData2.issues) } elseif ($issData2 -is [array]) { @($issData2) } else { @() }
        foreach ($iss in $issues2) {
            $num = if ($iss.project_issues_index) { $iss.project_issues_index } elseif ($iss.number) { $iss.number } else { "?" }
            if ($num -eq "?" -or $seenTriage.ContainsKey($num)) { continue }
            $created = if ($iss.created_at) { $iss.created_at } else { "" }
            $closed = if ($iss.closed_at) { $iss.closed_at } else { "" }
            $inPeriod = $false
            if ($created) { try { if (([DateTime]$created) -ge $periodStart) { $inPeriod = $true } } catch {} }
            if (-not $inPeriod -and $closed) { try { if (([DateTime]$closed) -ge $periodStart) { $inPeriod = $true } } catch {} }
            if (-not $inPeriod) { continue }

            $seenTriage[$num] = $true
            $title2 = if ($iss.subject) { $iss.subject } elseif ($iss.title) { $iss.title } else { "" }
            $desc2 = if ($iss.description) { $iss.description } else { "" }
            $author2 = if ($iss.author.login) { $iss.author.login } elseif ($iss.author.username) { $iss.author.username } else { "" }
            $issueId2 = if ($iss.id) { $iss.id } else { $num }

            # 检查是否已有标签
            $hasLabel = $false
            if ($iss.tags -and @($iss.tags).Count -gt 0) { $hasLabel = $true }

            # 关键词分类
            $combined2 = "$title2 $desc2".ToLower()
            $chosenLabel = ""
            if ($combined2 -match '(?i)bug|error|crash|fault|fix|缺陷|错误|异常|崩溃|修复|故障') {
                $chosenLabel = "缺陷"
            } elseif ($combined2 -match '(?i)feature|enhancement|add|新增|建议|功能|特性|新功能|支持|request') {
                $chosenLabel = "功能"
            } elseif ($combined2 -match '(?i)doc|readme|guide|wiki|tutorial|文档|说明|教程|手册') {
                $chosenLabel = "文档"
            } elseif ($combined2 -match '(?i)test|测试|用例|覆盖|验证') {
                $chosenLabel = "测试"
            } elseif ($combined2 -match '(?i)duplicate|重复|重复的') {
                $chosenLabel = "重复"
            } elseif ($combined2 -match '(?i)question|疑问|不确定|讨论|澄清|是否|可否') {
                $chosenLabel = "疑问"
            } elseif ($combined2 -match '(?i)help|协助|帮助|协作|请求帮助|互助') {
                $chosenLabel = "协助"
            } elseif ($combined2 -match '(?i)postpone|wontfix|暂缓|搁置|低优|不重要|不紧急|暂不|delay') {
                $chosenLabel = "搁置"
            } elseif ($combined2 -match '(?i)task|todo|任务|待办|计划|安排') {
                $chosenLabel = "任务"
            } elseif ($combined2 -match '(?i)support|兼容|环境|依赖|平台|适配') {
                $chosenLabel = "支持"
            }

            # 检查是否已有负责人
            $hasAssignee = $false
            if ($iss.assigned_to_id -and "$($iss.assigned_to_id)" -ne "0" -and "$($iss.assigned_to_id)" -ne "") { $hasAssignee = $true }
            if ($iss.assigned_to -and $iss.assigned_to.login) { $hasAssignee = $true }

            if ($chosenLabel -or -not $hasAssignee) {
                $triageItems += @{ num=$num; id=$issueId2; title=$title2; desc=$desc2; author=$author2; label=$chosenLabel; hasLabel=$hasLabel; hasAssignee=$hasAssignee }
            }
        }
    } catch {}
}

$labelOk = 0; $labelFail = 0; $labelSkip = 0
$assignOk = 0; $assignFail = 0; $assignSkip = 0

if ($triageItems.Count -gt 0) {
    Log-Step "Applying labels and assignees to $($triageItems.Count) issue(s)..."
    foreach ($item in $triageItems) {
        # -- 打标签 --
        if (-not $item.label) {
            $labelSkip++
        } elseif ($item.hasLabel) {
            Log-Info "  #$($item.num) already has label, skipping"
            $labelSkip++
        } elseif ($DryRun) {
            Log-Warn "  [DRY RUN] Would tag #$($item.num) with '$($item.label)'"
            $labelSkip++
        } else {
            $tgtId = $tagIdMap[$item.label]
            if (-not $tgtId) {
                Log-Warn "  #$($item.num): label '$($item.label)' not found in repo tags — create on website first"
                $labelFail++
            } else {
                $bodyJson = "{`"issue_tag_ids`":[$tgtId]}"
                $tagResult = Invoke-GL api,PATCH,"/v1/$Owner/$Repo/issues/$($item.id)",--body,$bodyJson
                if ($tagResult) {
                    try {
                        $tagOkFlag = (($tagResult | ConvertFrom-Json).ok -eq $true)
                    } catch { $tagOkFlag = $false }
                    if ($tagOkFlag) { Log-Ok "  #$($item.num) tagged: $($item.label)"; $labelOk++ } else { Log-Warn "  #$($item.num) tag failed"; $labelFail++ }
                } else { Log-Warn "  #$($item.num) tag failed (no response)"; $labelFail++ }
            }
        }

        # -- 分配责任人 (默认分配给 Issue 作者) --
        if ($item.hasAssignee) {
            $assignSkip++
        } elseif (-not $item.author -or $item.author -eq "?") {
            Log-Info "  #$($item.num): no author info, skipping assign"
            $assignSkip++
        } elseif ($DryRun) {
            Log-Warn "  [DRY RUN] Would assign #$($item.num) to @$($item.author)"
            $assignSkip++
        } else {
            # Resolve login name to numeric user ID
            $authorID = $null
            $isNum = $false
            try { [void][int]$item.author; $isNum = $true } catch {}
            if ($isNum) {
                $authorID = $item.author
            } else {
                $userJson = Invoke-GL api,GET,"/users/$($item.author)"
                if ($userJson) {
                    try {
                        $userData = ($userJson | ConvertFrom-Json).data
                        if ($userData.id) { $authorID = [int]$userData.id }
                        elseif ($userData.user_id) { $authorID = [int]$userData.user_id }
                    } catch {}
                }
            }
            if (-not $authorID) {
                Log-Warn "  #$($item.num): cannot resolve user ID for '@$($item.author)'"
                $assignFail++
            } else {
                $bodyJson = "{`"assigner_ids`":[$authorID]}"
                $assignResult = Invoke-GL api,PATCH,"/v1/$Owner/$Repo/issues/$($item.id)",--body,$bodyJson
                if ($assignResult) {
                    try {
                        $assignOkFlag = (($assignResult | ConvertFrom-Json).ok -eq $true)
                    } catch { $assignOkFlag = $false }
                    if ($assignOkFlag) { Log-Ok "  #$($item.num) assigned to @$($item.author) (ID:$authorID)"; $assignOk++ } else { Log-Warn "  #$($item.num) assign failed"; $assignFail++ }
                } else { Log-Warn "  #$($item.num) assign failed (no response)"; $assignFail++ }
            }
        }
    }
    Log-Ok "Labels: $labelOk applied, $labelFail failed, $labelSkip skipped"
    Log-Ok "Assign: $assignOk applied, $assignFail failed, $assignSkip skipped"
} else {
    Log-Info "No new issues require triage in this period"
}

# -- 贡献者汇总 --
$allContribs = @($prContributors.Keys; $issContributors.Keys) | Select-Object -Unique | Sort-Object
$contribText = if ($allContribs.Count -gt 0) { ($allContribs | ForEach-Object { "- @$_" }) -join "`n" } else { "(无活跃贡献者)" }

# ================================================================
# Phase 3: 生成 Release Notes (changelog skill 模板)
# ================================================================
Log-Title "Phase 3: Generate Release Notes"

$releaseBody = @"
# 🎉 Release $newVersion

## 📊变更统计
- **周期**: $periodStartStr ~ $periodEndStr
- **已合并 PR**: $prCount 个
- **Issue 活动**: $issCount 条（新增/关闭）
- **Commits**: $commitCount 条

## 📝 Issue 活动

### 🐛 缺陷 / Bug
$bugSection

### ✨ 新功能 / Feature
$featSection

### 📖 文档 / 其他
$docSection

### 💡 其他
$otherSection

## 🔀 已合并 PR
$prText

## 🙏 贡献者
$contribText

---
**完整变更日志**: https://www.gitlink.org.cn/$Owner/$Repo/compare/$prevTag...$newVersion

*Auto-generated by gitlink-cli community-ops workflow (gitlink-changelog skill)*
"@

Write-Host $releaseBody
Write-Host ""

# ================================================================
# Phase 4: 发布 Release
# ================================================================
Log-Title "Phase 4: Publish Release"

if ($DryRun) {
    Log-Warn "[DRY RUN] Would create release: $newVersion"
} else {
    Log-Step "Creating release $newVersion..."
    $relResult = Invoke-GL release,+create,--owner,$Owner,--repo,$Repo,--tag,$newVersion,--name,"Release $newVersion",--body,$releaseBody
    if ($relResult -and (Get-JsonOk ($relResult | ConvertFrom-Json))) {
        Log-Ok "Release $newVersion published!"
        Log-Info "View: https://www.gitlink.org.cn/$Owner/$Repo/releases"
    } else {
        Log-Warn "Release may have failed (tag might exist)"
    }
}

# ================================================================
# Phase 5: 发布社区周报 (覆盖更新同一天)
# ================================================================
Log-Title "Phase 5: Publish Weekly Report"

$wikiTitle = "社区周报"
$wikiBody = @"
# 社区周报 - $Owner/$Repo

**$periodStartStr ~ $periodEndStr**

---

## 📊 数据总览
- 已合并 PR: **$prCount** 个
- Issue 活动: **$issCount** 条
- 贡献者: $($allContribs.Count)

## 🔀 合并的 PR
$prText

## 📝 Issue 动态
$bugSection
$featSection
$docSection
$otherSection

---

*Auto-generated by gitlink-cli | $periodStartStr ~ $periodEndStr | Next report in ~$PeriodHours h*
"@

if ($DryRun) {
    Log-Warn "[DRY RUN] Would publish Wiki"
} else {
    Log-Step "Publishing to Wiki..."
    # 先尝试覆盖更新，不存在则新建
    $wikiResult = Invoke-GL wiki,+update,--owner,$Owner,--repo,$Repo,--title,$wikiTitle,--cover,$wikiBody
    if ($wikiResult -and (Get-JsonOk ($wikiResult | ConvertFrom-Json))) {
        Log-Ok "Weekly report updated on Wiki"
    } else {
        Log-Info "Page not found, creating new..."
        $wikiResult = Invoke-GL wiki,+create,--owner,$Owner,--repo,$Repo,--title,$wikiTitle,--content,$wikiBody
        if ($wikiResult -and (Get-JsonOk ($wikiResult | ConvertFrom-Json))) {
            Log-Ok "Weekly report created on Wiki"
        } else {
            Log-Warn "Wiki publish failed"
        }
    }
}

Log-Title "Complete"
Write-Host "  Release:    $newVersion" -ForegroundColor Green
Write-Host "  PRs merged: $prCount" -ForegroundColor Green
Write-Host "  Issues:     $issCount" -ForegroundColor Green
Write-Host "  Labels:     $labelOk applied / $labelFail failed / $labelSkip skipped" -ForegroundColor Green
Write-Host "  Assigned:   $assignOk applied / $assignFail failed / $assignSkip skipped" -ForegroundColor Green
Write-Host "  Contributors: $($allContribs.Count)" -ForegroundColor Green
Write-Host "  Wiki:       $wikiTitle" -ForegroundColor Green
