<#
  SFCraft 文档 · 物品贴图自动同步

  流程:
    1. 将 sfcraft 仓库 textures/item 目录下所有贴图同步到 assets/items
    2. 扫描 content 中所有 crafting 组件, 收集用到的物品 id
    3. 对本地缺失的 id, 从 Minecraft wiki 自动获取(按命名规则挑选最新版本)
    4. 仍有无法获取的 id 时, 列出并退出(返回码 1), 阻断 build / dev

  用法:
    powershell -ExecutionPolicy Bypass -File scripts\sync-items.ps1 [-Force]

  说明:
    - sfcraft 自定义贴图每次与远端比对大小, 缺失或变更时更新
    - 原版贴图只在本地缺失时下载, 不会覆盖手动放入 assets/items 的贴图
    - 需要联网访问 api.github.com / zh.minecraft.wiki
#>
[CmdletBinding()]
param(
  [switch]$Force
)

$ErrorActionPreference = 'Stop'

$repoRoot   = Split-Path -Parent $PSScriptRoot
$itemsDir   = Join-Path $repoRoot 'assets\items'
$contentDir = Join-Path $repoRoot 'content'
$ua         = 'sfcraft-docs-sync/1.0 (https://github.com/saltedfishclub/sfcraft-docs)'

New-Item -ItemType Directory -Path $itemsDir -Force | Out-Null

# ---------- 数据源 ----------
$sfOwner = 'saltedfishclub'
$sfRepo  = 'sfcraft'
$sfRef   = 'rev/26.2'
$sfDir   = 'src/main/resources/assets/sfcraft/textures/item'
$sfListUrl = "https://api.github.com/repos/$sfOwner/$sfRepo/contents/$sfDir`?ref=$sfRef"
$wikiApi   = 'https://zh.minecraft.wiki/api.php'
$wikiImg   = 'https://zh.minecraft.wiki/images/'

function Write-Step([string]$s) { Write-Host "`n== $s" -ForegroundColor Cyan }

function Invoke-Get([string]$url, [int]$maxRetry = 2) {
  for ($i = 0; ; $i++) {
    try {
      return Invoke-RestMethod -Uri $url -Headers @{ 'User-Agent' = $ua } -TimeoutSec 30
    } catch {
      if ($i -ge $maxRetry) { throw }
      Start-Sleep -Milliseconds 800
    }
  }
}

# ---------- 1. sfcraft 自定义贴图 ----------
Write-Step '1/4 同步 sfcraft 自定义贴图'
$sfCount = 0
$sfNew   = 0
try {
  $list = Invoke-Get $sfListUrl
  foreach ($f in $list) {
    $target = Join-Path $itemsDir $f.name
    $need = $Force -or
            -not (Test-Path -LiteralPath $target) -or
            ((Get-Item -LiteralPath $target).Length -ne [int64]$f.size)
    if ($need) {
      Invoke-WebRequest -Uri $f.download_url -Headers @{ 'User-Agent' = $ua } -OutFile $target -TimeoutSec 60
      $sfNew++
    }
    $sfCount++
  }
  Write-Host "  $sfCount 个文件, 本次更新 $sfNew 个"
} catch {
  Write-Host "  [警告] 无法访问 GitHub, 跳过 sfcraft 贴图同步: $($_.Exception.Message)" -ForegroundColor Yellow
}

# ---------- 2. 扫描 crafting 组件 ----------
Write-Step '2/4 扫描组件物品 id'
$ids = @{}
$shortcodePat = [regex]'(?s){{<[ ]*crafting\b(.*?)}}'
$pairPat      = [regex]'(\w+)="([^"]*)"'
$slotKeys     = @('a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'out')

function Add-ItemId([string]$raw) {
  $v = $raw.Trim()
  if ($v.Length -gt 0) {
    $id = ($v -split ':')[0].Trim()
    if ($id.Length -gt 0) { $ids[$id] = $true }
  }
}

Get-ChildItem -Path $contentDir -Recurse -Filter '*.md' -File | ForEach-Object {
  $text = Get-Content -LiteralPath $_.FullName -Raw -Encoding UTF8
  foreach ($m in $shortcodePat.Matches($text)) {
    $params = @{}
    foreach ($p in $pairPat.Matches($m.Groups[1].Value)) { $params[$p.Groups[1].Value] = $p.Groups[2].Value }
    foreach ($key in $slotKeys) {
      if ($params.ContainsKey($key)) { Add-ItemId $params[$key] }
    }
    if ($params.ContainsKey('pattern')) {
      $pat = $params['pattern'] -replace '\\n|;|\r?\n', ' '
      foreach ($tok in @($pat -split '\s+' | Where-Object { $_ })) {
        if ($tok -eq '.') { continue }
        if ($params.ContainsKey($tok)) { Add-ItemId $params[$tok] }
        elseif ($tok -match '^[a-z0-9_]+$') { Add-ItemId $tok }
      }
    }
  }
}

$all  = @($ids.Keys | Sort-Object)
$need = @($all | Where-Object { -not (Test-Path -LiteralPath (Join-Path $itemsDir "${_}.png")) })
Write-Host "  使用 $($all.Count) 个物品 id, 本地已有 $($all.Count - $need.Count) 个"

# ---------- 3. 从 Minecraft wiki 获取缺失贴图 ----------
Write-Step '3/4 从 Minecraft wiki 获取缺失贴图'

function Get-WikiCandidates([string]$name) {
  $regex = '^' + [regex]::Escape($name) + '(_\(item\))?_JE\d+(\.\d+)*(_BE\d+)?\.png$'
  # 两个查询互补:
  #   <name>_    宽前缀, 覆盖 (item) 等变体, 如 Diamond_Boots_(item)_JE3_BE2.png
  #   <name>_JE  窄前缀, 在宽前缀因数量被截断时兜底(裸物品如 diamond 的 JE 渲染排序靠前)
  $urls = @(
    "$wikiApi`?action=query&list=allimages&aiprefix=$([uri]::EscapeDataString($name + '_'))&ailimit=500&format=json",
    "$wikiApi`?action=query&list=allimages&aiprefix=$([uri]::EscapeDataString($name + '_JE'))&ailimit=200&format=json"
  )
  $seen = @{}
  $all = New-Object System.Collections.ArrayList
  foreach ($u in $urls) {
    try {
      $r = Invoke-Get $u
      if ($null -ne $r.query.allimages) {
        foreach ($n in $r.query.allimages) {
          if (-not $seen.ContainsKey($n.name)) {
            [void]$seen.Add($n.name, $true)
            [void]$all.Add($n.name)
          }
        }
      }
    } catch {
      Write-Host "  [警告] wiki 查询失败 ($name): $($_.Exception.Message)" -ForegroundColor Yellow
    }
    Start-Sleep -Milliseconds 250
  }
  return @($all | Where-Object { $_ -match $regex })
}

function Select-BestCandidate([string]$name, [string[]]$candidates) {
  $regex = '^' + [regex]::Escape($name) + '(_\(item\))?_JE(\d+)(\.\d+)*(_BE(\d+))?\.png$'
  $best = $null
  $bestKey = $null
  foreach ($c in $candidates) {
    $m = [regex]::Match($c, $regex)
    if (-not $m.Success) { continue }
    $key = @(
      $(if ($m.Groups[1].Success) { 1 } else { 0 }),          # 优先物品图标 (item)
      [int]$m.Groups[2].Value,                                 # JE 版本
      $(if ($m.Groups[5].Success) { [int]$m.Groups[5].Value } else { -1 })  # BE 版本
    )
    if ($null -eq $bestKey) { $best = $c; $bestKey = $key; continue }
    for ($i = 0; $i -lt 3; $i++) {
      if ($key[$i] -ne $bestKey[$i]) {
        if ($key[$i] -gt $bestKey[$i]) { $best = $c; $bestKey = $key }
        break
      }
    }
  }
  return $best
}

function Get-NameVariants([string]$id) {
  $words = @($id -split '_' | Where-Object { $_ })
  $title = @($words | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1) }) -join '_'

  $connectors = @('and', 'of', 'the', 'for', 'with', 'to', 'from', 'by', 'in', 'on', 'at')
  $mixed = @($words | ForEach-Object {
    if ($connectors -contains $_) { $_ } else { $_.Substring(0, 1).ToUpper() + $_.Substring(1) }
  }) -join '_'

  $variants = New-Object System.Collections.ArrayList
  [void]$variants.Add($title)
  if ($mixed -cne $title) { [void]$variants.Add($mixed) }
  if ($id.Length -le 4 -and $id -notmatch '[aeiou]') { [void]$variants.Add($id.ToUpper()) }
  $oneWord = @($words | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1) }) -join ''
  if ($oneWord -cne $title) { [void]$variants.Add($oneWord) }

  $aliases = @{
    'tnt'            = 'TNT'
    'tnt_minecart'   = 'TNT_Minecart'
    'dragon_breath'  = "Dragon's_Breath"
    'slime_ball'     = 'Slime'
    'snow_golem'     = 'Snow_Golem'
    'ocelot'         = 'Ocelot'
  }
  if ($aliases.ContainsKey($id)) { [void]$variants.Insert(0, $aliases[$id]) }
  return @($variants | Select-Object -Unique)
}

$failed = @()
foreach ($id in $need) {
  $file = $null
  foreach ($name in Get-NameVariants $id) {
    $cands = Get-WikiCandidates $name
    if ($cands.Count -gt 0) { $file = Select-BestCandidate $name $cands; break }
  }

  if ($file) {
    $target = Join-Path $itemsDir "$id.png"
    try {
      Invoke-WebRequest -Uri ($wikiImg + [uri]::EscapeDataString($file)) -Headers @{ 'User-Agent' = $ua } -OutFile $target -TimeoutSec 60
      $fs = [System.IO.File]::OpenRead($target)
      $sig = New-Object byte[] 8
      [void]$fs.Read($sig, 0, 8)
      $fs.Close()
      if (-not ($sig[0] -eq 137 -and $sig[1] -eq 80 -and $sig[2] -eq 78 -and $sig[3] -eq 71)) {
        throw '下载内容不是有效 PNG'
      }
      Write-Host "  ok    $id  <-  $file" -ForegroundColor Green
      continue
    } catch {
      Write-Host "  fail  $id  下载失败: $($_.Exception.Message)" -ForegroundColor Yellow
    }
  } else {
    Write-Host "  fail  $id  在 wiki 上未找到" -ForegroundColor Yellow
  }
  $failed += $id
}

# ---------- 4. 汇总错误 ----------
if ($failed.Count -gt 0) {
  Write-Host "`n[错误] 以下物品贴图无法自动获取:" -ForegroundColor Red
  $failed | Sort-Object | ForEach-Object { Write-Host "  - $_" -ForegroundColor Red }
  Write-Host @"

可能原因:
  1. 物品 id 拼写错误(组件中填写的是 assets/items 下的文件名)
  2. 该物品是 sfcraft 自定义物品, 但 textures/item 目录中没有同名贴图
  3. 原版物品在 Minecraft wiki 上的命名特殊, 未被自动规则覆盖

解决办法:
  - 将贴图手动放入 assets/items/<id>.png 后重新运行
  - 修正组件中的物品 id
  - 若是 wiki 命名特例, 可在 scripts/sync-items.ps1 的 Get-NameVariants 别名表中补充
"@ -ForegroundColor Yellow
  exit 1
}

Write-Host "`n全部贴图就绪 ✓" -ForegroundColor Green
exit 0
