cleanarch-new.ps1

#Requires -Version 5.1
[CmdletBinding(PositionalBinding=$false)]
param(
    [string]$ProjectName    = "",
    [ValidateSet("Dapper","EFCore","Hybrid","")]
    [string]$OrmMode        = "",
    [string[]]$Entities     = @("User", "Product"),
    [ValidateSet("MSSQL","Postgres")]
    [string]$DbProvider     = "",
    [string]$OutputRootPath = "",
    [switch]$SkipFrontend,
    [switch]$SkipAiGuide,
    [switch]$SkipTests,
    [switch]$SkipCi,
    [switch]$DryRun,
    [string]$IdeConfig      = "VSCode",
    [switch]$Observability,
    [switch]$NonInteractive,
    [string]$Language        = "tr",
    [ValidateSet("Web","Mobile","Both","")]
    [string]$Platform        = "",
    [ValidateSet("Layered","FeatureSliced")]
    [string]$Architecture    = "Layered",
    [switch]$SkipNpm,
    [switch]$Version,
    [Alias("h")]
    [switch]$Help
)

$FrontendMode = "ReactTS"
$MobileTooling = "Expo"
$ConnectionString = ""

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

$ScriptDir  = Split-Path -Parent $MyInvocation.MyCommand.Path
$ModulesDir = Join-Path $ScriptDir "modules"

# --- UTF-8 encoding (Türkçe karakter desteği) ---
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding            = [System.Text.Encoding]::UTF8

# --- Performance Optimizations (DotNet CLI) ---
$env:DOTNET_CLI_TELEMETRY_OPTOUT = "1"
$env:DOTNET_NOLOGO = "1"
$env:NUGET_XMLDOC_MODE = "skip"

$Global:DryRun = $DryRun

. "$ModulesDir\core\Utils.ps1"
. "$ModulesDir\core\Invoke-TuiMenu.ps1"
. "$ModulesDir\core\Get-Locale.ps1"
$L = Get-Locale -Language $Language

# Dil dogrulama
if ($Language -notin @('tr','en')) {
    Write-Host ""
    Write-Host "ERROR: Invalid language '$Language'. Use 'tr' for Turkish or 'en' for English." -ForegroundColor Red
    Write-Host "HATA: Gecersiz dil '$Language'. 'tr' (Turkce) veya 'en' (Ingilizce) kullanin." -ForegroundColor Red
    Write-Host ""
    Write-Host " cleanarch-new -Help" -ForegroundColor DarkGray
    Write-Host " cleanarch-new -h" -ForegroundColor DarkGray
    return
}

if ($Help) {
    Write-Host ""
    Write-Host " Clean Architecture Template Generator (cleanarch)" -ForegroundColor Cyan
    Write-Host " ------------------------------------------------" -ForegroundColor DarkCyan
    Write-Host ""
    Write-Host " USAGE / KULLANIM:" -ForegroundColor Yellow
    Write-Host " cleanarch-new -ProjectName <Name/Ad> -Platform Web|Mobile|Both [options]" -ForegroundColor White
    Write-Host " cleanarch-new # Interactive TUI / Etkilesimli menu" -ForegroundColor DarkGray
    Write-Host " cleanarch-new -h # This help / Bu yardim" -ForegroundColor DarkGray
    Write-Host ""
    Write-Host " PARAMETERS / PARAMETRELER:" -ForegroundColor Yellow
    Write-Host " -ProjectName <Name/Ad> : Project name / Proje adi" -ForegroundColor White
    Write-Host " -Platform <Web|Mobile|Both> : Target platform / Hedef platform" -ForegroundColor White
    Write-Host " -OrmMode <Dapper|EFCore|Hybrid> : ORM mode / ORM modu" -ForegroundColor White
    Write-Host " -DbProvider <MSSQL|Postgres> : Database provider / Veritabani saglayicisi" -ForegroundColor White
    Write-Host " -Entities <List> : Comma-separated entities / Virgulle ayrilmis entity listesi (default: User,Product)" -ForegroundColor White
    Write-Host " -Architecture <Layered|FeatureSliced> : Architecture style / Mimari yapi (default: Layered)" -ForegroundColor White
    Write-Host " -OutputRootPath <Path> : Output directory / Cikti dizini" -ForegroundColor White
    Write-Host " -Language <tr|en> : Interface language / Arayuz dili (default: tr)" -ForegroundColor White
    Write-Host " -IdeConfig <VSCode|None> : IDE configuration / IDE ayarları (default: VSCode)" -ForegroundColor White
    Write-Host ""
    Write-Host " OPTIONAL FLAGS / OPSIYONEL BAYRAKLAR:" -ForegroundColor Yellow
    Write-Host " -SkipFrontend : Skip frontend generation / Frontend olusturmayi atla" -ForegroundColor White
    Write-Host " -SkipTests : Skip test projects / Test projelerini atla" -ForegroundColor White
    Write-Host " -SkipCi : Skip CI/CD pipeline / CI/CD pipeline'ini atla" -ForegroundColor White
    Write-Host " -SkipAiGuide : Skip AI developer guide / AI rehberini atla" -ForegroundColor White
    Write-Host " -SkipNpm : Skip npm install (faster) / npm install calistirmayi atla (daha hizli)" -ForegroundColor White
    Write-Host " -DryRun : Simulate only / Sadece simulasyon yap" -ForegroundColor White
    Write-Host " -NonInteractive : Skip TUI menus, use defaults / Menuleri atla ve varsayilanlari kullan" -ForegroundColor White
    Write-Host " -Observability : Add Serilog + OpenTelemetry / Serilog ve OpenTelemetry destegi ekle" -ForegroundColor White
    Write-Host ""
    Write-Host " OTHER COMMANDS / DIGER KOMUTLAR:" -ForegroundColor Yellow
    Write-Host " cleanarch-version : Show version / Versiyon bilgisi" -ForegroundColor White
    Write-Host " cleanarch-update : Update to latest / Son surume guncelle" -ForegroundColor White
    Write-Host " cleanarch-uninstall : Remove from system / Sistemden kaldir" -ForegroundColor White
    Write-Host ""
    Write-Host " EXAMPLES / ORNEKLER:" -ForegroundColor Yellow
    Write-Host " cleanarch-new -ProjectName MyApp -Platform Web -OrmMode EFCore -DbProvider Postgres" -ForegroundColor DarkGray
    Write-Host " cleanarch-new -ProjectName MyApp -Platform Both -OrmMode Hybrid -DbProvider MSSQL -Language en" -ForegroundColor DarkGray
    Write-Host ""
    return
}


if ($Version) {

    $v = & "$ModulesDir\core\cleanarch-version.ps1" -OnlyVersion
    Write-Host "Clean Architecture Template Generator v$v"
    return
}


$TotalSw = [System.Diagnostics.Stopwatch]::StartNew()

if (-not $NonInteractive) { Clear-Host }
Write-Host "================================================" -ForegroundColor DarkCyan
Write-Host " Clean Architecture Template Generator " -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor DarkCyan
Write-Host ""

# --- Proje adi ---
if (-not $ProjectName) {
    if ($NonInteractive) { Write-Err $L.tuiNameRequired "E001"; exit 1 }
    $ProjectName = Read-Host $L.tuiProjectName
}
if (-not $ProjectName -or $ProjectName -match '[\s\\/]' -or $ProjectName -notmatch '^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$') {
    Write-Err $L.tuiInvalidName "E001"
    return
}


# --- Platform secimi ---
if (-not $Platform) {
    if ($NonInteractive) { $Platform = "Web" }
    else {
        $options = @(
            $L.tuiPlatformWeb,
            $L.tuiPlatformMobile,
            $L.tuiPlatformBoth
        )
        $choice = Invoke-TuiMenu -Title $L.tuiSelectPlatform -Options $options
        $Platform = switch ($choice) { 0 { "Web" } 1 { "Mobile" } 2 { "Both" } }
    }
}

# --- Architecture secimi ---
if (-not $Architecture) {
    if ($NonInteractive) { $Architecture = "Layered" }
    else {
        $options = @(
            $L.tuiArchLayered,
            $L.tuiArchFeature
        )
        $choice = Invoke-TuiMenu -Title $L.tuiSelectArch -Options $options
        $Architecture = switch ($choice) { 0 { "Layered" } 1 { "FeatureSliced" } }
    }
}

# --- ORM secimi ---
if (-not $OrmMode) {
    if ($NonInteractive) { $OrmMode = "EFCore" }
    else {
        $options = @(
            $L.tuiOrmDapper,
            $L.tuiOrmEfCore,
            $L.tuiOrmHybrid
        )
        $choice = Invoke-TuiMenu -Title $L.tuiSelectOrm -Options $options
        $OrmMode = switch ($choice) { 0 { "Dapper" } 1 { "EFCore" } 2 { "Hybrid" } }
    }
}

# --- Database secimi ---
if (-not $DbProvider) {
    if ($NonInteractive) { $DbProvider = "Postgres" }
    else {
        $options = @("MS SQL Server", "PostgreSQL")
        $choice = Invoke-TuiMenu -Title $L.tuiSelectDb -Options $options
        $DbProvider = switch ($choice) { 0 { "MSSQL" } 1 { "Postgres" } }
    }
}

$CiProvider = "GitHub"

# --- Entities string split (virgülle geçilen "Product,Order" -> @("Product","Order")) ---
if ($Entities.Count -eq 1 -and $Entities[0] -match ',') {
    $Entities = $Entities[0] -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
}

# --- 'User' entity'si Auth icin zorunludur ---
if ($Entities -notcontains "User") { $Entities += "User" }

# --- Cikti koku ---
if (-not $OutputRootPath) {
    $currentDir = (Get-Location).Path
    if ($NonInteractive) { $OutputRootPath = $currentDir }
    else {
        Write-Host ""
        Write-Host ($L.tuiProjectDir -f $currentDir) -ForegroundColor DarkGray
        $inputRoot = Read-Host $L.tuiDirPrompt
        $OutputRootPath = if ($inputRoot.Trim()) { $inputRoot.Trim() } else { $currentDir }
    }
}

if (-not $Global:DryRun -and -not (Test-Path $OutputRootPath)) {
    New-Item -ItemType Directory -Path $OutputRootPath -Force | Out-Null
}
$OutputRootPath = [System.IO.Path]::GetFullPath($OutputRootPath)
$OutputPath = Join-Path $OutputRootPath $ProjectName

if (-not $Global:DryRun -and (Test-Path $OutputPath)) {
    Write-Err ($L.tuiDirExists -f $OutputPath) "E002"
    return
}


# Params Splatting
$Params = @{
    ProjectName   = $ProjectName
    OrmMode       = $OrmMode
    DbProvider    = $DbProvider
    OutputPath    = $OutputPath
    FrontendMode  = $FrontendMode
    SkipFrontend  = $SkipFrontend
    SkipAiGuide   = $SkipAiGuide
    SkipTests     = $SkipTests
    SkipCi        = $SkipCi
    CiProvider    = $CiProvider
    DryRun        = $DryRun
    Entities      = $Entities
    IdeConfig     = $IdeConfig
    Observability = $Observability
    Language      = $Language
    Platform      = $Platform
    Architecture  = $Architecture
    MobileTooling    = $MobileTooling
    SkipNpm          = $SkipNpm
}

# --- Adimlar ---
& "$ModulesDir\core\Test-Prerequisites.ps1" -FrontendMode $FrontendMode -Language $Language
if ($LASTEXITCODE -ne 0) { exit 1 }

try {
    $BackendParams = $Params.Clone()
    $BackendParams.OutputPath = Join-Path $OutputPath "$ProjectName-backend"

    Invoke-Step $L.logCreatingSolution { & "$ModulesDir\solution\Initialize-Solution.ps1" @BackendParams }
    Invoke-Step $L.logInstallingNuget { & "$ModulesDir\solution\Install-Packages.ps1" @BackendParams }
    Invoke-Step $L.logDomain { & "$ModulesDir\backend\Write-DomainLayer.ps1" @BackendParams }
    Invoke-Step $L.logApplication { & "$ModulesDir\backend\Write-ApplicationLayer.ps1" @BackendParams }
    Invoke-Step $L.logInfrastructure { & "$ModulesDir\backend\Write-InfrastructureLayer.ps1" @BackendParams }

    Invoke-Step $L.logPersistence {
        & "$ModulesDir\backend\Write-Persistence-Shared.ps1" @BackendParams
        & "$ModulesDir\backend\Write-Persistence-Dapper.ps1" @BackendParams
        & "$ModulesDir\backend\Write-Persistence-EFCore.ps1" @BackendParams
        & "$ModulesDir\backend\Write-Persistence-Hybrid.ps1" @BackendParams
    }

    Invoke-Step $L.logWebApi { & "$ModulesDir\backend\Write-WebApiLayer.ps1" @BackendParams }

    if (-not $SkipTests) {
        Invoke-Step $L.logTests { & "$ModulesDir\testing\Write-TestLayer.ps1" @BackendParams }
    }

    if (-not $SkipFrontend) {
        $setupMsg = switch ($Platform) {
            "Web"    { $L.logFrontendSetup }
            "Mobile" { $L.logMobileSetup }
            "Both"   { $L.logBothSetup }
            default  { $L.logFrontendSetup }
        }
        $writeMsg = switch ($Platform) {
            "Web"    { $L.logFrontendFiles }
            "Mobile" { $L.logMobileFiles }
            "Both"   { $L.logBothFiles }
            default  { $L.logFrontendFiles }
        }
        Invoke-Step $setupMsg { & "$ModulesDir\solution\Install-Frontend.ps1" @Params }
        Invoke-Step $writeMsg { & "$ModulesDir\frontend\Write-Frontend.ps1" @Params }
    }

    Invoke-Step $L.logDocker { & "$ModulesDir\devops\Write-Docker.ps1" @Params }

    if ($IdeConfig -ne "None") {
        Invoke-Step "$IdeConfig configuration" { & "$ModulesDir\devops\Write-IdeConfig.ps1" @Params }
    }

    if (-not $SkipCi) {
        Invoke-Step $L.logCiCd { & "$ModulesDir\devops\Write-CiPipeline.ps1" @Params }
    }

    Invoke-Step $L.logMigrations { & "$ModulesDir\devops\Write-MigrationScript.ps1" @Params }
    Invoke-Step $L.logReadme { & "$ModulesDir\solution\Write-Readme.ps1" @Params }

    if (-not $SkipAiGuide) {
        Invoke-Step $L.logAiGuide {
            & "$ModulesDir\ai-guide\Write-AiGuide-Core.ps1" @Params
            & "$ModulesDir\ai-guide\Write-AiGuide-Domain.ps1" @Params
            & "$ModulesDir\ai-guide\Write-AiGuide-Application.ps1" @Params
            & "$ModulesDir\ai-guide\Write-AiGuide-Persistence.ps1" @Params
            & "$ModulesDir\ai-guide\Write-AiGuide-WebApi.ps1" @Params
            if ($Platform -match "Web|Both" -and -not $SkipFrontend) {
                & "$ModulesDir\ai-guide\Write-AiGuide-Web.ps1" @Params
            }
            if ($Platform -match "Mobile|Both" -and -not $SkipFrontend) {
                & "$ModulesDir\ai-guide\Write-AiGuide-Mobile.ps1" @Params
            }
        }
    }

    # Summary
    Write-Host ""
    Write-Host "================================================" -ForegroundColor Green
    Write-Host (" " + ($L.tuiReady -f $ProjectName)) -ForegroundColor Green
    Write-Host (" " + ($L.tuiTotalTime -f $TotalSw.Elapsed.TotalSeconds)) -ForegroundColor Green
    Write-Host "================================================" -ForegroundColor Green
    Write-Host ""
    Write-Host "$($L.tuiLocation) : $OutputPath"
    Write-Host "Platform : $Platform"
    Write-Host "ORM : $OrmMode"
    Write-Host "Database : $DbProvider"
    if ($Platform -match "Web|Both") {
        Write-Host "Frontend : $(if($SkipFrontend){'None'}else{$FrontendMode})"
    }
    if ($Platform -match "Mobile|Both") {
        Write-Host "Mobile : $(if($SkipFrontend){'None'}else{$MobileTooling})"
    }
    Write-Host "IDE : $IdeConfig"
    Write-Host ""

} catch {
    Write-Err ($L.tuiErrorOccurred -f $_) "E003"
    if (-not $Global:DryRun) {
        Write-Warn $L.tuiCleaningUp
        Remove-Item $OutputPath -Recurse -Force -ErrorAction SilentlyContinue
    }
    return
}