#!/bin/bash

# Usage: ./scaffold.sh MyProjectName [slnx|sln] [true|false for packages]
# Example: ./scaffold.sh MyCleanApp slnx

# --- 1. Setup & Validation ---
if [ -z "$1" ]; then
  echo "❌ Please provide a project name."
  echo "Usage: ./scaffold.sh MyProjectName [slnx|sln]"
  exit 1
fi

PROJECT_NAME=$1
FORMAT=${2:-slnx}
INSTALL_PACKAGES=${3:-true} # Default to true
SLN_FILE="$PROJECT_NAME.$FORMAT"

# Check if directory exists to avoid overwriting
if [ -d "$PROJECT_NAME" ]; then
    echo "❌ Directory '$PROJECT_NAME' already exists. Aborting."
    exit 1
fi

echo "🚀 Scaffolding $FORMAT solution for: $PROJECT_NAME (Clean Architecture + DDD)"

# Create Root Directory and enter it
mkdir "$PROJECT_NAME"
cd "$PROJECT_NAME" || exit

# --- 2. Smart SDK Detection ---
# Get the latest installed SDK version (e.g. 10.0.102)
LATEST_SDK=$(dotnet --list-sdks | tail -n 1 | awk '{print $1}')

if [ -n "$LATEST_SDK" ]; then
    echo "ℹ️  Detected SDK: $LATEST_SDK. Pinning global.json..."
    dotnet new globaljson --sdk-version "$LATEST_SDK" --roll-forward latestFeature
else
    echo "⚠️  No SDK detected. Skipping global.json."
fi

dotnet new gitignore

# --- 3. Create Solution & Fix NuGet ---
if [ "$FORMAT" == "slnx" ]; then
    dotnet new sln -n "$PROJECT_NAME" --format slnx
else
    dotnet new sln -n "$PROJECT_NAME"
fi

# [FIX] Create a local nuget.config to ensure we can find packages
echo "📦 Configuring NuGet sources..."
dotnet new nugetconfig --force

# Check if nuget.org is already there
if ! dotnet nuget list source --configfile "nuget.config" | grep -q "nuget.org"; then
    dotnet nuget add source "https://api.nuget.org/v3/index.json" -n "nuget.org" --configfile "nuget.config"
fi

# --- 4. Create Projects ---
echo "🔨 Creating projects..."
dotnet new classlib -n "$PROJECT_NAME.Domain" -o "src/$PROJECT_NAME.Domain"       
dotnet new classlib -n "$PROJECT_NAME.Application" -o "src/$PROJECT_NAME.Application"
dotnet new classlib -n "$PROJECT_NAME.Infrastructure" -o "src/$PROJECT_NAME.Infrastructure"
dotnet new webapi -n "$PROJECT_NAME.Api" -o "src/$PROJECT_NAME.Api" --use-controllers

mkdir -p tests
dotnet new xunit -n "$PROJECT_NAME.Domain.Tests" -o "tests/$PROJECT_NAME.Domain.Tests" 
dotnet new xunit -n "$PROJECT_NAME.Application.Tests" -o "tests/$PROJECT_NAME.Application.Tests"
dotnet new xunit -n "$PROJECT_NAME.IntegrationTests" -o "tests/$PROJECT_NAME.IntegrationTests"

# --- 4.1 CLEANUP BOILERPLATE --- 
echo "🧹 Removing default template files..."

# Define array of files to remove relative to solution root
FILES_TO_REMOVE=(
    "src/$PROJECT_NAME.Domain/Class1.cs"         
    "src/$PROJECT_NAME.Application/Class1.cs"
    "src/$PROJECT_NAME.Infrastructure/Class1.cs"
    "tests/$PROJECT_NAME.Domain.Tests/UnitTest1.cs" 
    "tests/$PROJECT_NAME.Application.Tests/UnitTest1.cs"
    "tests/$PROJECT_NAME.IntegrationTests/UnitTest1.cs"
    "src/$PROJECT_NAME.Api/WeatherForecast.cs"
    "src/$PROJECT_NAME.Api/Controllers/WeatherForecastController.cs"
    "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.http"
)

for file in "${FILES_TO_REMOVE[@]}"; do
    if [ -f "$file" ]; then
        rm "$file"
        echo "   - Deleted $file"
    fi
done

# --- 5. Add to Solution (With Visual Folders) ---
echo "📂 Organizing solution structure..."
# Source
dotnet sln "$SLN_FILE" add "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" -s "src" 
dotnet sln "$SLN_FILE" add "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" -s "src"
dotnet sln "$SLN_FILE" add "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" -s "src"
dotnet sln "$SLN_FILE" add "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" -s "src"

# Tests
dotnet sln "$SLN_FILE" add "tests/$PROJECT_NAME.Domain.Tests/$PROJECT_NAME.Domain.Tests.csproj" -s "tests" 
dotnet sln "$SLN_FILE" add "tests/$PROJECT_NAME.Application.Tests/$PROJECT_NAME.Application.Tests.csproj" -s "tests"
dotnet sln "$SLN_FILE" add "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" -s "tests"

# --- 6. Add References ---
echo "🔗 Wiring up dependencies..."

# Application -> Domain
dotnet add "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" 

# Infrastructure -> Application AND Domain
dotnet add "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" reference "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj"
dotnet add "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" 

# API -> Application AND Infrastructure
dotnet add "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" reference "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj"
dotnet add "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" reference "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj"

# Tests
dotnet add "tests/$PROJECT_NAME.Domain.Tests/$PROJECT_NAME.Domain.Tests.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" 

dotnet add "tests/$PROJECT_NAME.Application.Tests/$PROJECT_NAME.Application.Tests.csproj" reference "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj"
dotnet add "tests/$PROJECT_NAME.Application.Tests/$PROJECT_NAME.Application.Tests.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" 

dotnet add "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" reference "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj"
dotnet add "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" reference "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj"
dotnet add "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" reference "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj"
dotnet add "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" 

# --- 7. Install Nuget Packages (Optional) ---
if [ "$INSTALL_PACKAGES" = true ]; then
    echo "📦 Installing standard Clean Architecture packages..."

    # Helper function to add packages safely
    add_package() {
        local proj=$1
        local pkg=$2
        echo "   + Adding $pkg..."
        dotnet add "$proj" package "$pkg" > /dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo "   ⚠️  Failed to add $pkg. Check connection."
        fi
    }

    # Application Layer
    add_package "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" "MediatR"
    add_package "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" "FluentValidation"
    add_package "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" "FluentValidation.DependencyInjectionExtensions"
    add_package "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" "Microsoft.Extensions.Logging.Abstractions"

    # Infrastructure Layer
    add_package "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" "Microsoft.EntityFrameworkCore"
    add_package "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" "Microsoft.EntityFrameworkCore.SqlServer"
    add_package "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" "Microsoft.EntityFrameworkCore.Design"

    # API Layer
    add_package "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" "Microsoft.EntityFrameworkCore.Tools"

    # Tests
    TEST_PROJECTS=(
        "tests/$PROJECT_NAME.Domain.Tests/$PROJECT_NAME.Domain.Tests.csproj" 
        "tests/$PROJECT_NAME.Application.Tests/$PROJECT_NAME.Application.Tests.csproj"
        "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj"
    )

    for proj in "${TEST_PROJECTS[@]}"; do
        add_package "$proj" "FluentAssertions"
        add_package "$proj" "Moq"
    done

    add_package "tests/$PROJECT_NAME.IntegrationTests/$PROJECT_NAME.IntegrationTests.csproj" "Microsoft.AspNetCore.Mvc.Testing"
fi

# --- 8. Final Verification ---
echo "🏗️  Verifying build..."
dotnet build
if [ $? -eq 0 ]; then
    echo "✅ $PROJECT_NAME scaffolded successfully!"
    echo "👉 cd $PROJECT_NAME"
else
    echo "⚠️  Scaffolding finished, but build failed. Run 'dotnet restore' manually."
fi