modules/backend/Write-Persistence-Shared.ps1

param(
    [string]$ProjectName,
    [string]$OrmMode,
    [string]$DbProvider,
    [string]$OutputPath,
    [string[]]$Entities
)

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

$base = Join-Path $OutputPath "src\$ProjectName.Persistence"
function Write-File($rel, $con) { Write-CoreFile (Join-Path $base $rel) $con }
function T($template, $e = "") { 
    $res = $template.Replace("{P}", $ProjectName)
    if ($e) { $res = $res.Replace("{E}", $e) }
    return $res
}

# =====================================================================
# AppDbContext (EFCore ve Hybrid modlarda)
# =====================================================================
if ($OrmMode -eq "EFCore" -or $OrmMode -eq "Hybrid") {
    $dbSets = ""
    foreach ($e in $Entities) {
        $pE = Get-Plural $e
        $dbSets += " public DbSet<$e> $pE => Set<$e>();`n"
        
        if ($e -eq "User") {
            # BCrypt hash of "Admin123!" with work factor 12
            $bcryptHash = '$2a$12$4V.u4DaYV9N7BPMkbHBtuO18JGY.AQWcGGb4c39EDBxZz9eQXlZRK'
            Write-File "Configurations\UserConfiguration.cs" (T @"
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using {P}.Domain.Entities;
using {P}.Domain.ValueObjects;
 
namespace {P}.Persistence.Configurations;
 
public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.HasKey(u => u.Id);
        builder.Property(u => u.Username).HasMaxLength(100).IsRequired();
        builder.Property(u => u.Email)
               .HasConversion(
                   email => email.Value,
                   value => new Email(value))
               .HasMaxLength(255)
               .IsRequired();
        builder.HasQueryFilter(u => !u.IsDeleted);
        builder.HasData(new
        {
            Id = 1,
            Username = `"admin`",
            Email = new Email(`"admin@example.com`"),
            PasswordHash = `"$bcryptHash`",
            Role = `"Admin`",
            IsActive = true,
            CreatedAt = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            UpdatedAt = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            IsDeleted = false
        });
    }
}
"@
)
        } else {
            $extraConfig = if ($e -eq "Product") { "`r`n builder.Property(x => x.Price).HasColumnType(`"decimal(18,2)`").HasDefaultValue(0);" } else { "" }
            Write-File "Configurations\${e}Configuration.cs" (T @"
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using {P}.Domain.Entities;
 
namespace {P}.Persistence.Configurations;
 
public class ${e}Configuration : IEntityTypeConfiguration<$e>
{
    public void Configure(EntityTypeBuilder<$e> builder)
    {
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Name).HasMaxLength(200).IsRequired();$extraConfig
        builder.HasQueryFilter(x => !x.IsDeleted);
    }
}
"@
 $e)
        }
    }

    Write-File "Context\AppDbContext.cs" (T @"
using Microsoft.EntityFrameworkCore;
using {P}.Domain.Entities;
 
namespace {P}.Persistence.Context;
 
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
 
$dbSets
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
    }
}
"@
)
}

# =====================================================================
# ServiceRegistration
# =====================================================================
$registrations = ""
foreach ($e in $Entities) {
    $registrations += " services.AddScoped<I$e`Repository, $e`Repository>();`n"
}
$uowRegistration = if ($OrmMode -match "EFCore|Hybrid") { " services.AddScoped<IUnitOfWork, {P}.Persistence.UnitOfWork.UnitOfWork>();`n" } else { "" }

$efUsing = if ($OrmMode -ne "Dapper") { "`nusing Microsoft.EntityFrameworkCore;" } else { "" }
$usings = switch ($DbProvider) {
    "Postgres" { "using Npgsql;$efUsing" }
    default    { "using Microsoft.Data.SqlClient;$efUsing" }
}

$connRegistration = switch ($DbProvider) {
    "Postgres" { 
        $r = if ($OrmMode -ne "Dapper") { " services.AddDbContext<AppDbContext>(opt => opt.UseNpgsql(connStr));`n" } else { "" }
        $r += if ($OrmMode -ne "EFCore") { " services.AddScoped<IDbConnection>(_ => new NpgsqlConnection(connStr));" } else { "" }
        $r
    }
    default {
        $r = if ($OrmMode -ne "Dapper") { " services.AddDbContext<AppDbContext>(opt => opt.UseSqlServer(connStr));`n" } else { "" }
        $r += if ($OrmMode -ne "EFCore") { " services.AddScoped<IDbConnection>(_ => new SqlConnection(connStr));" } else { "" }
        $r
    }
}

$dapperTypeHandlerReg = ""
$dapperTypeHandlerDef = ""
if ($OrmMode -ne "EFCore") {
    $dapperTypeHandlerReg = " Dapper.SqlMapper.AddTypeHandler(new EmailTypeHandler());`n"
    $dapperTypeHandlerDef = T @"
 
public class EmailTypeHandler : Dapper.SqlMapper.TypeHandler<{P}.Domain.ValueObjects.Email>
{
    public override void SetValue(System.Data.IDbDataParameter parameter, {P}.Domain.ValueObjects.Email? value)
    {
        parameter.Value = value?.Value ?? (object)System.DBNull.Value;
    }
 
    public override {P}.Domain.ValueObjects.Email Parse(object value)
    {
        return new {P}.Domain.ValueObjects.Email(value.ToString() ?? string.Empty);
    }
}
"@

}

Write-File "ServiceRegistration\PersistenceServiceRegistration.cs" (T @"
using System.Data;
$usings
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using {P}.Domain.Interfaces;
using {P}.Persistence.Repositories;
$(if ($OrmMode -ne "Dapper") { "using {P}.Persistence.Context;" })
 
namespace {P}.Persistence.ServiceRegistration;
public static class PersistenceServiceRegistration {
    public static IServiceCollection AddPersistenceServices(this IServiceCollection services, IConfiguration configuration) {
$dapperTypeHandlerReg var connStr = configuration.GetConnectionString("DefaultConnection");
$connRegistration
$uowRegistration
$registrations return services;
    }
}
$dapperTypeHandlerDef
"@
)