#requires -Version 5
<#
.SYNOPSIS
    Refreshes pack.lock.json by querying Modrinth + CurseForge for the latest
    compatible version of each mod listed below.

.DESCRIPTION
    THIS SCRIPT MUTATES pack.lock.json. Run only when you intentionally want to
    bump versions (and remember to update the server to match).

    For non-mutating "what's available?" reports, run Check-Updates.ps1.

.PARAMETER PackName
.PARAMETER PackVersion
.PARAMETER MinecraftVersion
.PARAMETER LoaderType
.PARAMETER LoaderVersion
    Override pack metadata. Defaults read from existing lockfile if present.
#>

[CmdletBinding()]
param(
    [string]$PackName          = "",
    [string]$PackVersion       = "",
    [string]$MinecraftVersion  = "1.21.1",
    [string]$LoaderType        = "neoforge",
    [string]$LoaderVersion     = ""
)

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

$here     = Split-Path -Parent $MyInvocation.MyCommand.Path
$lockPath = Join-Path $here '..\pack\pack.lock.json'

# Read existing lock for defaults
$existing = if (Test-Path $lockPath) { Get-Content $lockPath -Raw | ConvertFrom-Json } else { $null }
if (-not $PackName     -and $existing) { $PackName     = $existing.name }
if (-not $PackVersion  -and $existing) { $PackVersion  = $existing.version }
if (-not $LoaderVersion -and $existing) { $LoaderVersion = $existing.loader.version }
if (-not $PackName)     { $PackName     = "Brass and Sigil" }
if (-not $PackVersion)  { $PackVersion  = "0.6.0" }
if (-not $LoaderVersion) { $LoaderVersion = "21.1.228" }

# ---------------------------------------------------------------------------
# Mod definitions: edit here when adding/removing mods. allowBeta=true allows
# fallback to beta if no release exists.
# ---------------------------------------------------------------------------
$modrinthMods = @(
    @{ slug = "create";              allowBeta = $false }
    @{ slug = "create-aeronautics";  allowBeta = $false }
    @{ slug = "sable";               allowBeta = $false }
    @{ slug = "create-big-cannons";  allowBeta = $false }
    @{ slug = "create-tfmg";         allowBeta = $false }
    @{ slug = "distanthorizons";     allowBeta = $true  }
    @{ slug = "sodium";              allowBeta = $false }
    @{ slug = "iris";                allowBeta = $false }
    @{ slug = "modernfix";           allowBeta = $false }
    @{ slug = "ferrite-core";        allowBeta = $false }
    @{ slug = "architectury-api";    allowBeta = $false }
    @{ slug = "rhino";               allowBeta = $true  }
    @{ slug = "rpl";                 allowBeta = $false }
    @{ slug = "kubejs";              allowBeta = $false }
    @{ slug = "jei";                 allowBeta = $true  }
    @{ slug = "jade";                allowBeta = $false }
    @{ slug = "chunky";              allowBeta = $false }
)

# CurseForge mods aren't auto-resolved (no public API without a key).
# Update fileId/version/filename here when bumping.
$curseforgeMods = @(
    @{
        slug     = "ftb-library"
        version  = "2101.1.31"
        fileId   = "7746959"
        path     = "mods/ftb-library-neoforge-2101.1.31.jar"
        url      = "https://mediafilez.forgecdn.net/files/7746/959/ftb-library-neoforge-2101.1.31.jar"
    }
    @{
        slug     = "ftb-teams"
        version  = "2101.1.9"
        fileId   = "7369021"
        path     = "mods/ftb-teams-neoforge-2101.1.9.jar"
        url      = "https://mediafilez.forgecdn.net/files/7369/21/ftb-teams-neoforge-2101.1.9.jar"
    }
    @{
        slug     = "ftb-chunks"
        version  = "2101.1.14"
        fileId   = "7608681"
        path     = "mods/ftb-chunks-neoforge-2101.1.14.jar"
        url      = "https://mediafilez.forgecdn.net/files/7608/681/ftb-chunks-neoforge-2101.1.14.jar"
    }
)

Add-Type -AssemblyName System.Web

function Invoke-Modrinth {
    param([string]$Path)
    Invoke-RestMethod -Uri "https://api.modrinth.com/v2$Path" -Headers @{ 'User-Agent' = 'BrassAndSigil-Launcher/0.1 (matt@sijbers.uk)' }
}

function Get-LatestModrinthVersion {
    param([string]$Slug, [bool]$AllowBeta)
    $encGv = [System.Web.HttpUtility]::UrlEncode('["' + $MinecraftVersion + '"]')
    $encL  = [System.Web.HttpUtility]::UrlEncode('["' + $LoaderType + '"]')
    $versions = Invoke-Modrinth ("/project/$Slug/version?game_versions=$encGv" + "&" + "loaders=$encL")
    if (-not $versions -or $versions.Count -eq 0) { return $null }
    if ($AllowBeta) {
        # Take the newest version regardless of stability (Modrinth orders newest first).
        return $versions[0]
    }
    # Stable-only: latest release version, or null if there's no release at all.
    return $versions | Where-Object { $_.version_type -eq 'release' } | Select-Object -First 1
}

$lockedMods = @()
$missing = @()

Write-Host ""
Write-Host "Querying Modrinth for $($modrinthMods.Count) mods (MC $MinecraftVersion / $LoaderType)..."
Write-Host ""

foreach ($mod in $modrinthMods) {
    try {
        $version = Get-LatestModrinthVersion -Slug $mod.slug -AllowBeta $mod.allowBeta
    } catch {
        Write-Warning "  [error]   $($mod.slug) - $($_.Exception.Message)"
        $missing += $mod.slug
        continue
    }
    if (-not $version) {
        Write-Warning "  [missing] $($mod.slug) - no compatible version"
        $missing += $mod.slug
        continue
    }
    $primary = $version.files | Where-Object { $_.primary -eq $true } | Select-Object -First 1
    if (-not $primary) { $primary = $version.files[0] }

    $lockedMods += [ordered]@{
        source    = "modrinth"
        slug      = $mod.slug
        versionId = $version.id
        version   = $version.version_number
        path      = "mods/$($primary.filename)"
        url       = $primary.url
        sha1      = $primary.hashes.sha1
        size      = $primary.size
    }

    $tag = if ($version.version_type -eq 'beta') { '[beta]   ' } else { '[release]' }
    Write-Host ("  $tag $($mod.slug.PadRight(22)) $($version.version_number.PadRight(28))")
}

Write-Host ""
Write-Host "Hashing $($curseforgeMods.Count) CurseForge mods (manual entries)..."
$tmpDir = Join-Path $env:TEMP "brassandsigil-cf-cache"
if (-not (Test-Path $tmpDir)) { New-Item -ItemType Directory -Path $tmpDir | Out-Null }

foreach ($cf in $curseforgeMods) {
    $fname = Split-Path -Leaf $cf.path
    $tmpFile = Join-Path $tmpDir $fname
    try {
        if (-not (Test-Path $tmpFile)) {
            Invoke-WebRequest -Uri $cf.url -OutFile $tmpFile -UseBasicParsing -Headers @{ 'User-Agent' = 'BrassAndSigil-Launcher/0.1 (matt@sijbers.uk)' }
        }
        $sha1 = (Get-FileHash -Algorithm SHA1 -Path $tmpFile).Hash.ToLowerInvariant()
        $size = (Get-Item $tmpFile).Length

        $lockedMods += [ordered]@{
            source   = "curseforge"
            slug     = $cf.slug
            fileId   = $cf.fileId
            version  = $cf.version
            path     = $cf.path
            url      = $cf.url
            sha1     = $sha1
            size     = $size
        }
        Write-Host ("  [cforge]  $($cf.slug.PadRight(22)) $($cf.version)")
    }
    catch {
        Write-Warning "  [error]   $fname - $($_.Exception.Message)"
        $missing += $fname
    }
}

$lock = [ordered]@{
    '$schema'   = "Brass-and-Sigil pack.lock.json - generated, do not edit by hand unless you know what you are doing"
    name        = $PackName
    version     = $PackVersion
    minecraft   = $MinecraftVersion
    loader      = [ordered]@{ type = $LoaderType; version = $LoaderVersion }
    lockedAt    = (Get-Date -Format 'o')
    mods        = $lockedMods
}

$json = $lock | ConvertTo-Json -Depth 10
[System.IO.File]::WriteAllText($lockPath, $json, [System.Text.UTF8Encoding]::new($false))

Write-Host ""
Write-Host "Lockfile written: $lockPath"
Write-Host ("  Total mods: {0}" -f $lockedMods.Count)
if ($missing.Count -gt 0) {
    Write-Warning "Missing: $($missing -join ', ')"
}
Write-Host ""
Write-Host "Run Build-Pack.ps1 next to generate the manifest."
