<#
.SYNOPSIS
    M88am の配布用 zip を作る。

.DESCRIPTION
    Release ビルドを行い、ソース一式とビルド済みバイナリをまとめた zip を出力する。

    zip の中身:

        README.md
        CHANGES.md            改変内容の明示 (M88 のライセンス条項が要求するもの)
        bin\
            M88.exe
            diskdrv.m88
            shaders\
                crt.hlsl      CRT フィルタは実行時に .hlsl を読むので必須
                palette.hlsl
        M88am-src\            git archive によるソース一式 (.md はここに置かない)

    ソース側は git archive で取り出すので、.gitattributes の export-ignore が
    効く (docs/ と CLAUDE.md は入らない)。コミットされていない変更は入らない。

    ROM (PC88.ROM 等) と e1.rom は同梱しない。README.md / CHANGES.md を参照。

.PARAMETER Version
    zip のファイル名に使う版数。既定は当日の日付 (yyyyMMdd)。

.PARAMETER OutDir
    zip の出力先。既定はリポジトリ直下の dist\ 。

.PARAMETER SkipBuild
    ビルドを行わず、既にある x64\Release\ の成果物をそのまま使う。

.PARAMETER Ref
    ソースを取り出す git のリビジョン。既定は HEAD。

.EXAMPLE
    powershell -NoProfile -ExecutionPolicy Bypass -File tools\make-dist.ps1

.NOTES
    終了コード 0 = 成功 / 1 = 失敗
#>

[CmdletBinding()]
param(
    [string]$Version = (Get-Date -Format 'yyyyMMdd'),
    [string]$OutDir  = '',
    [switch]$SkipBuild,
    [string]$Ref = 'HEAD'
)

$ErrorActionPreference = 'Stop'

function Fail($msg) {
    Write-Host "ERROR: $msg" -ForegroundColor Red
    exit 1
}

# ---------------------------------------------------------------------------
#   リポジトリのルートへ移動する
# ---------------------------------------------------------------------------
$root = & git rev-parse --show-toplevel
if ($LASTEXITCODE -ne 0) { Fail 'git リポジトリの中で実行してください' }
$root = $root -replace '/', '\'
Set-Location $root

Write-Host "Repository : $root"
Write-Host "Version    : $Version"
Write-Host "Source ref : $Ref"

if ([string]::IsNullOrWhiteSpace($OutDir)) {
    $OutDir = Join-Path $root 'dist'
}
if (-not (Test-Path $OutDir)) {
    New-Item -ItemType Directory -Path $OutDir -Force | Out-Null
}

# ---------------------------------------------------------------------------
#   コミットされていない変更があると、同梱ソースと同梱バイナリが食い違う
# ---------------------------------------------------------------------------
$dirty = & git status --porcelain
if ($LASTEXITCODE -ne 0) { Fail 'git status に失敗しました' }
if ($dirty) {
    Write-Host ''
    Write-Host '警告: コミットされていない変更があります。' -ForegroundColor Yellow
    Write-Host '      同梱するソース (git archive) にはこれらが入りません。' -ForegroundColor Yellow
    Write-Host '      ビルド済みバイナリとソースが食い違う可能性があります。' -ForegroundColor Yellow
    $dirty -split "`n" | ForEach-Object { Write-Host "        $_" -ForegroundColor Yellow }
    Write-Host ''
}

# ---------------------------------------------------------------------------
#   ビルド
#   M88.exe が起動していると自分自身と diskdrv.m88 をロックしてリンクが
#   失敗する (LNK1104)。動作確認の終了忘れなので、黙って落としてよい
#   (CLAUDE.md 「M88.exe が起動しているとビルドが失敗する」参照)
# ---------------------------------------------------------------------------
if (-not $SkipBuild) {
    $running = Get-Process -Name 'M88' -ErrorAction SilentlyContinue
    if ($running) {
        Write-Host '起動中の M88.exe を終了します (ビルドの妨げになるため)' -ForegroundColor Yellow
        Stop-Process -InputObject $running -Force
        Start-Sleep -Milliseconds 500
    }

    Write-Host ''
    Write-Host '--- ビルド (Release|x64) ---'
    & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $root 'tools\build.ps1') -Config Release
    if ($LASTEXITCODE -ne 0) { Fail "ビルドに失敗しました (exit $LASTEXITCODE)" }
}

# ---------------------------------------------------------------------------
#   同梱するバイナリ
# ---------------------------------------------------------------------------
$rel = Join-Path $root 'x64\Release'

$binfiles = @(
    @{ Src = Join-Path $rel 'M88.exe';                 Dst = 'M88.exe' }
    @{ Src = Join-Path $rel 'diskdrv.m88';             Dst = 'diskdrv.m88' }
    @{ Src = Join-Path $rel 'shaders\crt.hlsl';        Dst = 'shaders\crt.hlsl' }
    @{ Src = Join-Path $rel 'shaders\palette.hlsl';    Dst = 'shaders\palette.hlsl' }
)

foreach ($f in $binfiles) {
    if (-not (Test-Path $f.Src)) {
        Fail ("必要な成果物がありません: " + $f.Src + " (先にビルドしてください)")
    }
}

# ---------------------------------------------------------------------------
#   ステージング
# ---------------------------------------------------------------------------
$stage = Join-Path ([System.IO.Path]::GetTempPath()) ("M88am-dist-" + [System.Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $stage -Force | Out-Null

try {
    # --- ソース (git archive。export-ignore が効く) ---
    Write-Host ''
    Write-Host '--- ソースの取り出し ---'
    $srczip = Join-Path $stage '_src.zip'
    & git archive --format=zip --prefix=M88am-src/ -o $srczip $Ref
    if ($LASTEXITCODE -ne 0) { Fail 'git archive に失敗しました' }

    Expand-Archive -Path $srczip -DestinationPath $stage -Force
    Remove-Item $srczip -Force

    $srcdir = Join-Path $stage 'M88am-src'
    if (-not (Test-Path $srcdir)) { Fail 'ソースの展開に失敗しました' }

    # --- README.md / CHANGES.md は zip のルートへ「移動」する ---
    #     アーカイブを開いたときに readme が直下に見えないと分かりにくいため。
    #     配布物は1つの zip で完結しているので、改変内容の明示 (CHANGES.md) が
    #     ルートにあれば M88 のライセンス条項は満たせる
    foreach ($doc in @('README.md', 'CHANGES.md')) {
        $from = Join-Path $srcdir $doc
        if (-not (Test-Path $from)) { Fail "$doc が見つかりません" }
        Move-Item $from (Join-Path $stage $doc) -Force
    }

    # --- bin\ ---
    Write-Host '--- バイナリの収集 ---'
    $bindir = Join-Path $stage 'bin'
    New-Item -ItemType Directory -Path (Join-Path $bindir 'shaders') -Force | Out-Null
    foreach ($f in $binfiles) {
        Copy-Item $f.Src (Join-Path $bindir $f.Dst) -Force
        Write-Host ("  bin\" + $f.Dst)
    }

    # --- zip ---
    $outzip = Join-Path $OutDir ("M88am-" + $Version + ".zip")
    if (Test-Path $outzip) { Remove-Item $outzip -Force }

    Write-Host ''
    Write-Host '--- 圧縮 ---'
    Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $outzip -CompressionLevel Optimal

    # --- 結果 ---
    $info = Get-Item $outzip
    Write-Host ''
    Write-Host '=== 完成 ===' -ForegroundColor Green
    Write-Host ("  {0}  ({1:N0} bytes)" -f $info.FullName, $info.Length)

    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $zip = [System.IO.Compression.ZipFile]::OpenRead($outzip)
    try {
        $names = $zip.Entries | ForEach-Object { $_.FullName }
        Write-Host ("  収録ファイル数: {0}" -f $names.Count)
        Write-Host '  ルート:'
        $names | ForEach-Object { ($_ -split '[/\\]')[0] } | Sort-Object -Unique |
            ForEach-Object { Write-Host "    $_" }

        # 入ってはいけないものが混ざっていないか
        $ng = $names | Where-Object {
            $_ -match '(?i)\.rom$' -or $_ -match '(?i)(^|[/\\])M88\.ini$' -or
            $_ -match '(?i)(^|[/\\])docs[/\\]' -or $_ -match '(?i)(^|[/\\])CLAUDE\.md$'
        }
        if ($ng) {
            Write-Host ''
            Write-Host '  警告: 配布対象外のはずのファイルが含まれています' -ForegroundColor Yellow
            $ng | ForEach-Object { Write-Host "    $_" -ForegroundColor Yellow }
        }
    }
    finally {
        $zip.Dispose()
    }
}
finally {
    if (Test-Path $stage) { Remove-Item $stage -Recurse -Force }
}

exit 0
