#requires -Version 7
<#
.SYNOPSIS
    Populate the `side` field on each mod entry in pack.lock.json by querying
    Modrinth's project metadata. Run once after schema migration; thereafter,
    Update-Pack.ps1 should set side automatically when adding new mods.

.DESCRIPTION
    Modrinth returns `client_side` and `server_side` per project, with values
    `required` / `optional` / `unsupported` / `unknown`. We map:
      server_side = unsupported          -> side = "client"   (skip on server)
      client_side = unsupported          -> side = "server"   (skip on launcher)
      both required/optional/unknown     -> side = "both"     (install everywhere)

    Conservative: only marks a mod side-restricted when the OTHER side is
    explicitly `unsupported`. Anything ambiguous stays "both".

    CurseForge mods can't be queried (no API key here) -- left at "both" by
    default, manual edit if needed.

.PARAMETER LockPath
    pack.lock.json to update in place. Defaults to ../pack/pack.lock.json.

.PARAMETER DryRun
    Print proposed changes without writing the file.
#>

[CmdletBinding()]
param(
    [string]$LockPath = $(Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) '..\pack\pack.lock.json'),
    [switch]$DryRun
)

$ErrorActionPreference = 'Stop'
$ProgressPreference    = 'SilentlyContinue'

$LockPath = (Resolve-Path $LockPath).Path
$json = Get-Content $LockPath -Raw | ConvertFrom-Json -Depth 20

if (-not $json.mods) { throw "pack.lock.json has no 'mods' array." }

function Get-ModrinthSide {
    param([string]$Slug)
    $proj = Invoke-RestMethod -Uri "https://api.modrinth.com/v2/project/$Slug" `
                              -Headers @{ 'User-Agent' = 'BrassAndSigil-Launcher/0.1 (matt@sijbers.uk)' }
    $cs = $proj.client_side; $ss = $proj.server_side
    if ($ss -eq 'unsupported' -and $cs -ne 'unsupported')      { return 'client' }
    elseif ($cs -eq 'unsupported' -and $ss -ne 'unsupported')  { return 'server' }
    else                                                       { return 'both'   }
}

Write-Host ""
Write-Host "Bootstrapping side field on $($json.mods.Count) mods..."
Write-Host ""

$changes = 0
foreach ($mod in $json.mods) {
    $existing = if ($mod.PSObject.Properties.Name -contains 'side') { $mod.side } else { $null }
    if ($mod.source -ne 'modrinth') {
        # CurseForge or other: default to 'both' if missing, leave alone otherwise.
        if (-not $existing) {
            $mod | Add-Member -NotePropertyName 'side' -NotePropertyValue 'both' -Force
            Write-Host ("  [{0}] {1,-26} {2}" -f $mod.source.PadRight(7).Substring(0,7), $mod.slug, 'both (default; non-modrinth)')
            $changes++
        }
        continue
    }
    try {
        $side = Get-ModrinthSide -Slug $mod.slug
    } catch {
        Write-Warning ("  $($mod.slug) lookup failed: $($_.Exception.Message) -- leaving as 'both'")
        $side = 'both'
    }
    if ($existing -ne $side) {
        $mod | Add-Member -NotePropertyName 'side' -NotePropertyValue $side -Force
        Write-Host ("  [{0}] {1,-26} {2}" -f $mod.source.PadRight(7).Substring(0,7), $mod.slug, $side)
        $changes++
    } else {
        Write-Host ("  [{0}] {1,-26} {2} (unchanged)" -f $mod.source.PadRight(7).Substring(0,7), $mod.slug, $side) -ForegroundColor DarkGray
    }
    Start-Sleep -Milliseconds 100  # be polite to Modrinth's API
}

Write-Host ""
Write-Host "$changes mod(s) updated."

if ($DryRun) {
    Write-Host "DryRun: not writing $LockPath." -ForegroundColor DarkGray
    exit 0
}

# Round-trip via JSON: Modrinth-returned ConvertFrom-Json objects don't always
# round-trip with consistent property order, so we serialise with sorted keys
# at the mod level to keep the lockfile diff minimal.
$json | ConvertTo-Json -Depth 20 | Set-Content -Path $LockPath -Encoding utf8
Write-Host "Wrote $LockPath" -ForegroundColor Green
