param(
    [ValidateSet("web", "tauri")]
    [string]$Target = "web",
    [ValidateSet("Release", "Debug")]
    [string]$Configuration = "Release",
    [ValidateSet("none", "nsis", "msi")]
    [string]$TauriBundles = "none",
    [switch]$InstallDeps,
    [switch]$SkipInstall,
    [switch]$DryRun
)

$commonScript = Join-Path $PSScriptRoot "script-common.ps1"
if (-not (Test-Path $commonScript)) {
    throw "Missing helper script: $commonScript"
}
. $commonScript

$repoRoot = Resolve-JournalRepoRoot -StartPath $PSScriptRoot
$appRoot = Resolve-JournalAppRoot -RepoRoot $repoRoot

Clear-JournalProxyEnv

# Keep npm cache and temp local to the repo.
$npmCacheDir = Join-Path $repoRoot ".npm\cache"
$npmTempDir = Join-Path $repoRoot ".tmp\npm-temp"
New-Item -ItemType Directory -Force -Path $npmCacheDir, $npmTempDir | Out-Null
$env:npm_config_cache = $npmCacheDir
$env:npm_config_update_notifier = "false"
$env:npm_config_fund = "false"
$env:npm_config_audit = "false"
$env:npm_config_offline = "false"
$env:npm_config_prefer_offline = "false"
$env:npm_config_prefer_online = "true"
$env:TEMP = $npmTempDir
$env:TMP = $npmTempDir

if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
    throw "npm is required but was not found in PATH."
}

$nodeModulesPath = Join-Path $appRoot "node_modules"
$packageJsonPath = Join-Path $appRoot "package.json"
$packageLockPath = Join-Path $appRoot "package-lock.json"
$depsHashPath = Join-Path $appRoot "node_modules\.journal-deps.sha256"

function Get-JournalNodeDepsHash {
    param(
        [Parameter(Mandatory = $true)]
        [string[]]$Paths
    )

    $hashLines = foreach ($path in $Paths) {
        if (-not (Test-Path $path)) {
            continue
        }
        (Get-FileHash -Algorithm SHA256 -Path $path).Hash
    }
    return ($hashLines -join "`n").Trim()
}

$hashInputs = @()
if (Test-Path $packageJsonPath) {
    $hashInputs += $packageJsonPath
}
if (Test-Path $packageLockPath) {
    $hashInputs += $packageLockPath
}
if ($hashInputs.Count -eq 0) {
    throw "package.json not found under $appRoot."
}

$expectedDepsHash = Get-JournalNodeDepsHash -Paths $hashInputs
$shouldInstall = $InstallDeps -or (-not (Test-Path $nodeModulesPath))
$installReason = $null

if (-not $shouldInstall -and -not $SkipInstall) {
    if (-not (Test-Path $depsHashPath)) {
        $shouldInstall = $true
        $installReason = "dependency hash missing"
    }
    else {
        $currentDepsHash = (Get-Content $depsHashPath -Raw).Trim()
        if ($currentDepsHash -ne $expectedDepsHash) {
            $shouldInstall = $true
            $installReason = "package.json/lockfile changed"
        }
    }
}

if ($SkipInstall) {
    $shouldInstall = $false
    if ($installReason) {
        Write-Host "SkipInstall set; dependencies may be stale ($installReason)." -ForegroundColor Yellow
    }
}

Write-Host "Building Journal.App target '$Target' ($Configuration)..." -ForegroundColor Cyan
Write-Host "Using app root: $appRoot" -ForegroundColor DarkGray

Push-Location $appRoot
try {
    if ($shouldInstall) {
        $installArgs = if (Test-Path $packageLockPath) {
            @("ci", "--no-audit", "--fund=false")
        }
        else {
            @("install", "--no-audit", "--fund=false")
        }

        if ($installReason) {
            Write-Host "Dependencies changed ($installReason). Installing..." -ForegroundColor Yellow
        }

        Write-Host "> npm $($installArgs -join ' ')" -ForegroundColor DarkGray
        if (-not $DryRun) {
            & npm @installArgs
            if ($LASTEXITCODE -ne 0) {
                throw "Dependency install failed with exit code $LASTEXITCODE."
            }

            $depsDir = Split-Path $depsHashPath -Parent
            if (-not (Test-Path $depsDir)) {
                New-Item -ItemType Directory -Force -Path $depsDir | Out-Null
            }
            $expectedDepsHash | Set-Content -Path $depsHashPath -NoNewline
        }
    }
    else {
        Write-Host "Skipping dependency install (node_modules present and deps unchanged)." -ForegroundColor DarkGray
    }

    if ($Target -eq "web") {
        $buildArgs = @("run", "build")
        Write-Host "> npm $($buildArgs -join ' ')" -ForegroundColor DarkGray
        if (-not $DryRun) {
            & npm @buildArgs
            if ($LASTEXITCODE -ne 0) {
                throw "Frontend build failed with exit code $LASTEXITCODE."
            }
        }

        $outputPath = Join-Path $appRoot "build"
        if ($DryRun) {
            Write-Host "`nDry run complete (no commands executed)." -ForegroundColor Yellow
            Write-Host "Expected output: $outputPath" -ForegroundColor Gray
        }
        else {
            Write-Host "`nFrontend build successful." -ForegroundColor Green
            Write-Host "Output: $outputPath" -ForegroundColor Gray
        }
    }
    else {
        $tauriArgs = @("run", "tauri", "build")
        $tauriCliArgs = @()
        if ($TauriBundles -eq "none") {
            $tauriCliArgs += "--no-bundle"
        }
        else {
            $tauriCliArgs += @("--bundles", $TauriBundles)
        }
        if ($Configuration -eq "Debug") {
            $tauriCliArgs += "--debug"
        }
        if ($tauriCliArgs.Count -gt 0) {
            $tauriArgs += "--"
            $tauriArgs += $tauriCliArgs
        }

        Write-Host "> npm $($tauriArgs -join ' ')" -ForegroundColor DarkGray
        if (-not $DryRun) {
            & npm @tauriArgs
            if ($LASTEXITCODE -ne 0) {
                throw "Tauri build failed with exit code $LASTEXITCODE."
            }
        }

        $targetConfigDir = if ($Configuration -eq "Debug") { "debug" } else { "release" }
        $tauriTargetPath = Join-Path $appRoot "src-tauri\target"
        $rawExePath = Join-Path $tauriTargetPath "$targetConfigDir\journalapp.exe"
        if ($DryRun) {
            Write-Host "`nDry run complete (no commands executed)." -ForegroundColor Yellow
            if ($TauriBundles -eq "none") {
                Write-Host "Expected executable: $rawExePath" -ForegroundColor Gray
            }
            else {
                Write-Host "Expected output root: $tauriTargetPath" -ForegroundColor Gray
            }
        }
        else {
            Write-Host "`nTauri build successful." -ForegroundColor Green
            if ($TauriBundles -eq "none") {
                if (Test-Path $rawExePath) {
                    Write-Host "Executable location: $rawExePath" -ForegroundColor Gray
                }
                else {
                    $exeCandidates = Get-ChildItem -Path (Join-Path $tauriTargetPath $targetConfigDir) -File -Filter *.exe -ErrorAction SilentlyContinue |
                        Sort-Object LastWriteTime -Descending
                    if ($exeCandidates -and $exeCandidates.Count -gt 0) {
                        Write-Host "Executable location: $($exeCandidates[0].FullName)" -ForegroundColor Gray
                    }
                    else {
                        Write-Host "Output root: $tauriTargetPath" -ForegroundColor Gray
                    }
                }
            }
            else {
                Write-Host "Output root: $tauriTargetPath" -ForegroundColor Gray
            }
        }
    }
}
finally {
    Pop-Location
}

