param(
    [switch]$SkipZip,
    [switch]$SkipInstaller,
    [switch]$SkipRequirements,
    [switch]$Sign,
    [string]$CertThumbprint,
    [string]$PfxPath,
    [string]$PfxPassword,
    [string]$TimestampServer = "http://timestamp.digicert.com"
)

$ErrorActionPreference = "Stop"
$script:SignatureSummary = "Non signé"

function Write-Step {
    param([string]$Message)
    Write-Host ""
    Write-Host "=== $Message ===" -ForegroundColor Cyan
}

function Require-Path {
    param(
        [string]$PathValue,
        [string]$Label
    )
    if (-not (Test-Path $PathValue)) {
        throw "$Label introuvable: $PathValue"
    }
}

function Invoke-BootstrapPython {
    param([string[]]$Arguments)
    if ($script:PythonBootstrap[0] -eq "py") {
        & py $script:PythonBootstrap[1] @Arguments
    } else {
        & $script:PythonBootstrap[0] @Arguments
    }
}

function Resolve-BootstrapPython {
    if (Get-Command py -ErrorAction SilentlyContinue) {
        try {
            & py -3.11 --version | Out-Host
            if ($LASTEXITCODE -eq 0) {
                return @("py", "-3.11")
            }
        } catch {}
        try {
            & py -3 --version | Out-Host
            if ($LASTEXITCODE -eq 0) {
                return @("py", "-3")
            }
        } catch {}
    }
    if (Get-Command python -ErrorAction SilentlyContinue) {
        & python --version | Out-Host
        if ($LASTEXITCODE -eq 0) {
            return @("python")
        }
    }
    throw "Python introuvable sur la machine de build Windows."
}

function Resolve-SignTool {
    $command = Get-Command signtool.exe -ErrorAction SilentlyContinue
    if ($command) {
        return $command.Source
    }

    $programFilesX86 = ${env:ProgramFiles(x86)}
    if ($programFilesX86) {
        $kitsRoot = Join-Path $programFilesX86 "Windows Kits\10\bin"
        if (Test-Path $kitsRoot) {
            $candidates = @(
                Get-ChildItem -Path $kitsRoot -Recurse -Filter signtool.exe -ErrorAction SilentlyContinue |
                    Where-Object { $_.FullName -match "\\x64\\signtool\.exe$" } |
                    Sort-Object FullName -Descending
            )
            if ($candidates.Count -gt 0) {
                return $candidates[0].FullName
            }
        }
    }

    throw "signtool.exe introuvable. Installer Windows SDK ou ajouter signtool.exe au PATH."
}

function Resolve-InnoCompiler {
    $command = Get-Command ISCC.exe -ErrorAction SilentlyContinue
    if ($command) {
        return $command.Source
    }

    $candidates = @()
    if (${env:ProgramFiles(x86)}) {
        $candidates += (Join-Path ${env:ProgramFiles(x86)} "Inno Setup 6\ISCC.exe")
    }
    if ($env:ProgramFiles) {
        $candidates += (Join-Path $env:ProgramFiles "Inno Setup 6\ISCC.exe")
    }
    if ($env:LOCALAPPDATA) {
        $candidates += (Join-Path $env:LOCALAPPDATA "Programs\Inno Setup 6\ISCC.exe")
        $candidates += (Join-Path $env:LOCALAPPDATA "Inno Setup 6\ISCC.exe")
    }
    foreach ($candidate in $candidates) {
        if ($candidate -and (Test-Path $candidate)) {
            return $candidate
        }
    }

    return $null
}

function Invoke-CodeSigning {
    param([string]$FilePath)

    if (-not $Sign) {
        Write-Host "Signature Authenticode ignorée. Utiliser -Sign pour signer l'exécutable."
        return
    }

    Require-Path -PathValue $FilePath -Label "Fichier à signer"
    if ($PfxPath) {
        Require-Path -PathValue $PfxPath -Label "Certificat PFX"
    }

    $signTool = Resolve-SignTool
    Write-Host "SignTool : $signTool"

    if ($CertThumbprint -eq "REMPLACER_PAR_L_EMPREINTE_DU_CERTIFICAT") {
        throw "Empreinte de certificat non renseignée dans build_signing.local.ps1."
    }

    $args = @("sign", "/fd", "SHA256", "/tr", $TimestampServer, "/td", "SHA256", "/d", "Anonymisation")
    if ($PfxPath) {
        $args += @("/f", $PfxPath)
        if ($PfxPassword) {
            $args += @("/p", $PfxPassword)
        }
    } elseif ($CertThumbprint) {
        $args += @("/sha1", ($CertThumbprint -replace "\s", ""))
    } else {
        $args += @("/a")
    }
    $args += $FilePath

    & $signTool @args
    if ($LASTEXITCODE -ne 0) {
        throw "La signature Authenticode a échoué."
    }

    & $signTool verify /pa /v $FilePath
    if ($LASTEXITCODE -ne 0) {
        throw "La vérification Authenticode a échoué."
    }

    $signature = Get-AuthenticodeSignature $FilePath
    $subject = ""
    if ($signature.SignerCertificate) {
        $subject = $signature.SignerCertificate.Subject
    }
    $script:SignatureSummary = "$($signature.Status) - $subject"
    Write-Host "Signature : $script:SignatureSummary"

    if ($signature.Status -ne "Valid") {
        throw "Signature Authenticode non valide : $($signature.Status)"
    }
}

$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ProjectRoot = (Resolve-Path (Join-Path $ScriptDir "..")).Path
$SigningConfigPath = Join-Path $ProjectRoot "build_signing.local.ps1"
$SpecPath = Join-Path $ProjectRoot "anonymisation_onefile.spec"
$InstallerScriptPath = Join-Path $ProjectRoot "installer\Anonymisation.iss"
$BuildInfoPath = Join-Path $ProjectRoot "build_info.py"
$ModelPath = Join-Path $ProjectRoot "models\camembert-bio-deid\onnx\model.onnx"
$VenvDir = Join-Path $ProjectRoot ".venv_build_win"
$VenvPython = Join-Path $VenvDir "Scripts\python.exe"
$DistDir = Join-Path $ProjectRoot "dist"
$BuildDir = Join-Path $ProjectRoot "build"
$ReleaseDir = Join-Path $ProjectRoot "release"
$ExePath = Join-Path $DistDir "Anonymisation.exe"
$PackageDir = Join-Path $ReleaseDir "Anonymisation-Windows"
$ZipPath = Join-Path $ReleaseDir "Anonymisation-Windows.zip"
$HashPath = Join-Path $ReleaseDir "Anonymisation.exe.sha256.txt"
$InstallerPath = Join-Path $ReleaseDir "Anonymisation-Setup.exe"
$ReadmePath = Join-Path $PackageDir "README.txt"
$RequiredSourceFiles = @(
    "launcher.py",
    "Pseudonymisation_Gui_V5.py",
    "anonymizer_core_refactored_onnx.py",
    "admin_rules.py",
    "config_defaults.py",
    "profile_defaults.py",
    "gui_batch_paths.py",
    "manual_masking.py",
    "pdf_mask_designer.py",
    "format_converter.py",
    "camembert_ner_manager.py"
)

Write-Step "Préparation du build Windows"
Write-Host "Projet : $ProjectRoot"

Require-Path -PathValue $SpecPath -Label "Spec PyInstaller"
Require-Path -PathValue $InstallerScriptPath -Label "Script installateur Inno Setup"
Require-Path -PathValue $ModelPath -Label "Modèle ONNX embarqué"
foreach ($RelativeSourceFile in $RequiredSourceFiles) {
    Require-Path -PathValue (Join-Path $ProjectRoot $RelativeSourceFile) -Label "Module source requis"
}

if (Test-Path $SigningConfigPath) {
    Write-Step "Configuration locale de signature"
    . $SigningConfigPath
    if ($BuildSigningEnabled) { $Sign = $true }
    if ($BuildSigningCertThumbprint -and -not $CertThumbprint) { $CertThumbprint = $BuildSigningCertThumbprint }
    if ($BuildSigningPfxPath -and -not $PfxPath) { $PfxPath = $BuildSigningPfxPath }
    if ($BuildSigningPfxPassword -and -not $PfxPassword) { $PfxPassword = $BuildSigningPfxPassword }
    if ($BuildSigningTimestampServer -and $TimestampServer -eq "http://timestamp.digicert.com") {
        $TimestampServer = $BuildSigningTimestampServer
    }
    if ($Sign) {
        Write-Host "Signature activée depuis build_signing.local.ps1"
    }
}

Write-Step "Détection de Python"
$script:PythonBootstrap = Resolve-BootstrapPython
Write-Host "Bootstrap Python : $($script:PythonBootstrap -join ' ')"

Write-Step "Environnement virtuel de build"
if (-not (Test-Path $VenvPython)) {
    Write-Host "Création du venv : $VenvDir"
    Invoke-BootstrapPython -Arguments @("-m", "venv", $VenvDir)
}
Require-Path -PathValue $VenvPython -Label "Python du venv"

Push-Location $ProjectRoot
try {
    Write-Step "Installation des dépendances de build"
    & $VenvPython -m pip install --upgrade pip setuptools wheel
    if (-not $SkipRequirements) {
        & $VenvPython -m pip install -r requirements.txt
    }
    & $VenvPython -m pip install pyinstaller

    Write-Step "Génération de build_info.py"
    $commit = "local"
    $branch = "local"
    if (Get-Command git -ErrorAction SilentlyContinue) {
        try {
            $gitCommit = (git rev-parse --short HEAD 2>$null | Out-String).Trim()
            if ($gitCommit) { $commit = $gitCommit }
            $gitBranch = (git rev-parse --abbrev-ref HEAD 2>$null | Out-String).Trim()
            if ($gitBranch) { $branch = $gitBranch }
        } catch {}
    }
    $buildDate = Get-Date -Format "yyyy-MM-dd HH:mm"
    $buildInfo = @"
"""Métadonnées de build - généré automatiquement par build_windows_oneclick.ps1."""
BUILD_DATE = "$buildDate"
BUILD_COMMIT = "$commit"
BUILD_BRANCH = "$branch"
"@
    Set-Content -Path $BuildInfoPath -Value $buildInfo -Encoding UTF8
    Write-Host "Build info : $buildDate / $branch / $commit"

    Write-Step "Nettoyage des anciens artefacts"
    foreach ($PathValue in @($BuildDir, $DistDir, $PackageDir)) {
        if (Test-Path $PathValue) {
            Remove-Item -Recurse -Force $PathValue -ErrorAction SilentlyContinue
        }
    }
    if (Test-Path $ZipPath) {
        Remove-Item -Force $ZipPath -ErrorAction SilentlyContinue
    }
    if (Test-Path $HashPath) {
        Remove-Item -Force $HashPath -ErrorAction SilentlyContinue
    }
    if (Test-Path $InstallerPath) {
        Remove-Item -Force $InstallerPath -ErrorAction SilentlyContinue
    }

    Write-Step "Compilation PyInstaller"
    & $VenvPython -m PyInstaller --clean --noconfirm $SpecPath
    if ($LASTEXITCODE -ne 0) {
        throw "PyInstaller a échoué avec le code $LASTEXITCODE."
    }

    Write-Step "Vérification de l'exécutable"
    Require-Path -PathValue $ExePath -Label "Exécutable Windows"
    $exeSizeMb = [math]::Round((Get-Item $ExePath).Length / 1MB, 1)
    Write-Host "EXE créé : $ExePath ($exeSizeMb MB)"

    Write-Step "Signature Authenticode"
    Invoke-CodeSigning -FilePath $ExePath

    Write-Step "Préparation du dossier de livraison"
    New-Item -ItemType Directory -Force -Path $PackageDir | Out-Null
    Copy-Item $ExePath (Join-Path $PackageDir "Anonymisation.exe")

    $readme = @"
Anonymisation - paquet Windows
================================

Fichier principal :
- Anonymisation.exe

Conseils de diffusion :
- Aucune installation de Python n'est nécessaire pour l'utilisateur final.
- Conservez le fichier dans un dossier en écriture (par exemple Bureau ou Documents).
- Privilégiez une diffusion par partage réseau interne, Intune, GPO ou portail établissement.
- Évitez l'envoi direct par e-mail ou téléchargement public non signé.
- Le journal applicatif s'écrit à côté de l'exécutable : anonymisation.log

Build :
- Date : $buildDate
- Branche : $branch
- Commit : $commit
- Signature : $script:SignatureSummary
"@
    Set-Content -Path $ReadmePath -Value $readme -Encoding UTF8

    $hash = (Get-FileHash -Algorithm SHA256 $ExePath).Hash
    Set-Content -Path $HashPath -Value "SHA256  Anonymisation.exe  $hash" -Encoding UTF8
    Write-Host "SHA256 : $hash"

    if (-not $SkipZip) {
        Write-Step "Création de l'archive de livraison"
        Compress-Archive -Path (Join-Path $PackageDir "*") -DestinationPath $ZipPath -CompressionLevel Optimal
        Write-Host "Archive créée : $ZipPath"
    }

    if (-not $SkipInstaller) {
        Write-Step "Création de l'installateur Windows"
        $innoCompiler = Resolve-InnoCompiler
        if ($innoCompiler) {
            Write-Host "Inno Setup Compiler : $innoCompiler"
            $installerVersion = (Get-Date -Format "yyyy.MM.dd.HHmm")
            & $innoCompiler "/DAppVersion=$installerVersion" $InstallerScriptPath
            if ($LASTEXITCODE -ne 0) {
                throw "Inno Setup a échoué avec le code $LASTEXITCODE."
            }
            Require-Path -PathValue $InstallerPath -Label "Installateur Windows"
            $installerSizeMb = [math]::Round((Get-Item $InstallerPath).Length / 1MB, 1)
            Write-Host "Installateur créé : $InstallerPath ($installerSizeMb MB)"

            if ($Sign) {
                Write-Step "Signature Authenticode de l'installateur"
                Invoke-CodeSigning -FilePath $InstallerPath
            }
        } else {
            Write-Warning "Inno Setup 6 introuvable. Installateur ignoré. Installer Inno Setup puis relancer le build."
            Write-Warning "Téléchargement officiel : https://jrsoftware.org/isdl.php"
        }
    }

    Write-Step "Build terminé"
    Write-Host "EXE final : $ExePath" -ForegroundColor Green
    if (-not $SkipZip) {
        Write-Host "Archive prête : $ZipPath" -ForegroundColor Green
    }
    if ((-not $SkipInstaller) -and (Test-Path $InstallerPath)) {
        Write-Host "Installateur prêt : $InstallerPath" -ForegroundColor Green
    }
    Write-Host "Hash SHA256 : $HashPath" -ForegroundColor Green
} finally {
    Pop-Location
}
