modules/solution/Install-Packages.ps1

param(
    [string]$ProjectName,
    [string]$OrmMode,
    [string]$DbProvider,
    [string]$OutputPath,
    [bool]$SkipTests = $false,
    [bool]$Observability = $false
)

. (Join-Path (Split-Path $MyInvocation.MyCommand.Path) "..\core\Utils.ps1")

$src   = Join-Path $OutputPath "src"
$tests = Join-Path $OutputPath "tests"

$Packages = @{
    "Application"    = @(
        @{ Id = "MediatR"; Ver = "12.4.1" },
        @{ Id = "AutoMapper"; Ver = "13.0.1" },
        @{ Id = "FluentValidation"; Ver = "11.10.0" },
        @{ Id = "FluentValidation.DependencyInjectionExtensions"; Ver = "11.10.0" }
    )
    "Infrastructure" = @(
        @{ Id = "BCrypt.Net-Next"; Ver = "4.0.3" },
        @{ Id = "System.IdentityModel.Tokens.Jwt"; Ver = "8.1.2" },
        @{ Id = "Microsoft.AspNetCore.Authentication.JwtBearer"; Ver = "8.0.10" }
    )
    "Persistence"    = @(
        @{ Id = "Microsoft.Extensions.Configuration.Abstractions"; Ver = "8.0.0" }
    )

    "WebApi"         = @(
        @{ Id = "Microsoft.Extensions.Diagnostics.HealthChecks"; Ver = "8.0.10" }
    )

}

if (-not $SkipTests) {
    $Packages["Domain.Tests"] = @( @{ Id = "FluentAssertions"; Ver = "6.12.2" } )
    $Packages["Application.Tests"] = @( @{ Id = "Moq"; Ver = "4.20.72" }, @{ Id = "FluentAssertions"; Ver = "6.12.2" } )
    $Packages["Integration.Tests"] = @( @{ Id = "Microsoft.AspNetCore.Mvc.Testing"; Ver = "8.0.10" }, @{ Id = "FluentAssertions"; Ver = "6.12.2" } )
}

if ($OrmMode -match "Dapper|Hybrid") {
    $Packages["Persistence"] += @{ Id = "Dapper"; Ver = "2.1.35" }
    switch ($DbProvider) {
        "Postgres" { $Packages["Persistence"] += @{ Id = "Npgsql"; Ver = "8.0.5" } }
        default    { $Packages["Persistence"] += @{ Id = "Microsoft.Data.SqlClient"; Ver = "5.2.2" } }
    }
}

if ($OrmMode -match "EFCore|Hybrid") {
    $Packages["Persistence"] += @(
        @{ Id = "Microsoft.EntityFrameworkCore"; Ver = "8.0.10" },
        @{ Id = "Microsoft.EntityFrameworkCore.Tools"; Ver = "8.0.10" }
    )
    $Packages["WebApi"] += @(
        @{ Id = "Microsoft.EntityFrameworkCore.Design"; Ver = "8.0.10" }
    )
    switch ($DbProvider) {
        "Postgres" { $Packages["Persistence"] += @{ Id = "Npgsql.EntityFrameworkCore.PostgreSQL"; Ver = "8.0.10" } }
        default    { $Packages["Persistence"] += @{ Id = "Microsoft.EntityFrameworkCore.SqlServer"; Ver = "8.0.10" } }
    }
    $Packages["WebApi"] += @{ Id = "Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore"; Ver = "8.0.10" }
}

if ($Observability) {
    $Packages["WebApi"] += @(
        @{ Id = "Serilog.AspNetCore"; Ver = "8.0.3" },
        @{ Id = "Serilog.Sinks.Console"; Ver = "6.0.0" },
        @{ Id = "OpenTelemetry.Extensions.Hosting"; Ver = "1.9.0" },
        @{ Id = "OpenTelemetry.Instrumentation.AspNetCore"; Ver = "1.9.0" },
        @{ Id = "OpenTelemetry.Instrumentation.Http"; Ver = "1.9.0" },
        @{ Id = "OpenTelemetry.Exporter.Console"; Ver = "1.9.0" }
    )

    $Packages["Infrastructure"] += @(
        @{ Id = "Serilog.AspNetCore"; Ver = "8.0.3" },
        @{ Id = "Serilog.Sinks.Console"; Ver = "6.0.0" }
    )
}






function Add-PackagesToCsproj($csprojPath, $pkgs) {
    if ($Global:DryRun) {
        foreach ($p in $pkgs) { Write-Host " [PLAN] Add package $($p.Id) to $(Split-Path $csprojPath -Leaf)" -ForegroundColor DarkGray }
        return
    }
    if (-not (Test-Path $csprojPath)) { return }
    [xml]$xml = Get-Content $csprojPath
    
    $itemGroup = $xml.CreateElement("ItemGroup")
    foreach ($p in $pkgs) {
        $ref = $xml.CreateElement("PackageReference")
        $ref.SetAttribute("Include", $p.Id)
        $ref.SetAttribute("Version", $p.Ver)
        $itemGroup.AppendChild($ref) | Out-Null
    }
    $xml.Project.AppendChild($itemGroup) | Out-Null
    $xml.Save($csprojPath)
}

function Add-FrameworkRefToCsproj($csprojPath, $refName) {
    if ($Global:DryRun -or -not (Test-Path $csprojPath)) { return }
    [xml]$xml = Get-Content $csprojPath
    if ($xml.Project.InnerXml -match "FrameworkReference.*Include=`"$refName`"") { return }
    $ig = $xml.CreateElement("ItemGroup")
    $fr = $xml.CreateElement("FrameworkReference")
    $fr.SetAttribute("Include", $refName)
    $ig.AppendChild($fr) | Out-Null
    $xml.Project.AppendChild($ig) | Out-Null
    $xml.Save($csprojPath)
}

foreach ($layer in $Packages.Keys) {
    $csproj = if ($layer -match "Tests$") { Join-Path $tests "$ProjectName.$layer\$ProjectName.$layer.csproj" } else { Join-Path $src "$ProjectName.$layer\$ProjectName.$layer.csproj" }
    Add-PackagesToCsproj $csproj $Packages[$layer]
}

$infraCsproj = Join-Path $src "$ProjectName.Infrastructure\$ProjectName.Infrastructure.csproj"
Add-FrameworkRefToCsproj $infraCsproj "Microsoft.AspNetCore.App"

Invoke-Cmd "dotnet" "restore `"$OutputPath\$ProjectName.sln`""