#!/bin/bash

# --- 0. Determine Project Name ---
# Grab the name of the current directory
PROJECT_NAME=$(basename "$PWD")

echo "📂 Using current directory name as project name: $PROJECT_NAME"

# --- 1. Configuration ---
FORMAT="slnx"            # Options: "sln" or "slnx"
INSTALL_PACKAGES=true    # Set to true to install NuGet packages

echo "🚀 Initializing $PROJECT_NAME (Format: $FORMAT)..."

# --- 1.5 Database Selection ---
echo ""
echo "🗄️  Select your Database Provider for $PROJECT_NAME:"
echo "  1) PostgreSQL (Npgsql) [Default]"
echo "  2) SQL Server"
echo "  3) SQLite"
# < /dev/tty allows interactive prompt when piping via curl
read -p "Enter choice [1-3] (Default: 1): " DB_CHOICE < /dev/tty

case $DB_CHOICE in
    2)
        DB_PACKAGE="Microsoft.EntityFrameworkCore.SqlServer"
        echo "   Selected: SQL Server"
        ;;
    3)
        DB_PACKAGE="Microsoft.EntityFrameworkCore.Sqlite"
        echo "   Selected: SQLite"
        ;;
    *)
        DB_PACKAGE="Npgsql.EntityFrameworkCore.PostgreSQL"
        echo "   Selected: PostgreSQL"
        ;;
esac
echo ""

# --- 2. Smart SDK Detection ---
# Get the latest installed SDK version
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
    echo "📄 Creating .slnx solution..."
    dotnet new sln -n "$PROJECT_NAME" --format slnx
    SLN_FILE="$PROJECT_NAME.slnx"
else
    echo "📄 Creating standard .sln solution..."
    dotnet new sln -n "$PROJECT_NAME"
    SLN_FILE="$PROJECT_NAME.sln"
fi

# 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 not, add it
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.Shared" -o "src/$PROJECT_NAME.Shared"
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..."

FILES_TO_REMOVE=(
    "src/$PROJECT_NAME.Shared/Class1.cs"
    "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 in $SLN_FILE..."

dotnet sln "$SLN_FILE" add "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.csproj" -s "src"
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"

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..."

# Shared References
dotnet add "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj" reference "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.csproj"
dotnet add "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" reference "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.csproj"
dotnet add "src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj" reference "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.csproj"
dotnet add "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" reference "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.csproj"

# Clean Architecture Flow
dotnet add "src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj" reference "src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj"

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"

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"

# Test References
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.Domain.Tests/$PROJECT_NAME.Domain.Tests.csproj" reference "src/$PROJECT_NAME.Shared/$PROJECT_NAME.Shared.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.Shared/$PROJECT_NAME.Shared.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.Shared/$PROJECT_NAME.Shared.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..."

    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" "$DB_PACKAGE"
    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"
    add_package "src/$PROJECT_NAME.Api/$PROJECT_NAME.Api.csproj" "Serilog.AspNetCore"

    # Test Projects
    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!"
else
    echo "⚠️  Scaffolding finished, but build failed. Run 'dotnet restore' manually."
fi