modules/ai-guide/Write-AiGuide-Domain.ps1

param(
    [string]   $ProjectName,
    [string]   $OutputPath,
    [string[]] $Entities      = @("User", "Product")
)

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

$guideDir = Join-Path $OutputPath "ai-guide"
function Write-Guide($fileName, $content) {
    Write-CoreFile (Join-Path $guideDir $fileName) $content
}

$allEntitiesStr  = $Entities -join ", "

$domainGuideContent = @'
# Domain Layer AI Developer Guide
 
You are an AI assistant helping developers build the Domain Layer of the {P} solution.
This layer contains the enterprise business rules, entities, aggregate roots, value objects, and repository interfaces.
 
---
 
## Strict Domain Layer Rules
 
1. **No External Dependencies:** The Domain project must be 100% pure C#. Do not import packages from other layers, database libraries, or web packages.
2. **Encapsulation:** Properties on entities must use private or protected setters (`get; private set;` or `get; protected set;`). Avoid public setters.
3. **Rich Domain Models:** Do not create anemic entities. All changes to the entity state should occur through explicit domain methods (e.g. `ChangeEmail(Email email)`, `Activate()`).
4. **Aggregate Roots:** Key standalone entities are Aggregate Roots. They must implement the `IAggregateRoot` marker interface.
5. **Value Objects:** Use immutable Value Objects (inheriting from `ValueObject.cs`) for complex types that do not have identities but have business rules (e.g., `Email`).
6. **Self-Validation:** Validate invariants in constructor and domain methods. Throw exceptions (like `ArgumentException`) on invalid values.
 
---
 
## Existing Entities
 
The following entities are already scaffolded in this project: **{Entities}**
Use them as reference patterns when adding new entities.
 
- **User** - Full DDD Aggregate Root with `Email` Value Object. Methods: `UpdateRole()`, `ChangeEmail()`, `Activate()`, `Deactivate()`.
- **Product** - Rich Domain Model. Methods: `UpdateDetails(name, price)`.
 
---
 
## Common Base Types
 
### 1. BaseEntity.cs
All entities inherit from `BaseEntity`. It encapsulates identity, creation, update, and soft-delete states:
```csharp
public abstract class BaseEntity {
    public int Id { get; protected set; }
    public DateTime CreatedAt { get; protected set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; protected set; } = DateTime.UtcNow;
    public bool IsDeleted { get; protected set; } = false;
    public DateTime? DeletedAt { get; protected set; }
 
    public virtual void Delete() {
        if (!IsDeleted) {
            IsDeleted = true;
            DeletedAt = DateTime.UtcNow;
            UpdatedAt = DateTime.UtcNow;
        }
    }
}
```
 
### 2. ValueObject.cs
Provides base comparison logic for structural equality:
```csharp
public abstract class ValueObject {
    protected abstract IEnumerable<object?> GetEqualityComponents();
 
    public override bool Equals(object? obj) {
        if (obj == null || obj.GetType() != GetType()) return false;
        var other = (ValueObject)obj;
        return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
    }
 
    public override int GetHashCode() {
        return GetEqualityComponents()
            .Select(x => x != null ? x.GetHashCode() : 0)
            .Aggregate((x, y) => x ^ y);
    }
}
```
 
### 3. IAggregateRoot.cs
Marker interface to identify Aggregate Roots:
```csharp
public interface IAggregateRoot { }
```
 
---
 
## How to Add/Modify a Domain Model
 
When asked to add a new entity (e.g., `Category`), write it as a Rich Domain Model:
 
### 1. Entity Implementation
```csharp
// {P}-backend/src/{P}.Domain/Entities/Category.cs
using {P}.Domain.Common;
 
namespace {P}.Domain.Entities;
 
public class Category : BaseEntity, IAggregateRoot
{
    public string Name { get; private set; } = string.Empty;
 
    // Required for ORM mapping (EF Core & Dapper)
    protected Category()
    {
    }
 
    // Invariant-enforcing constructor
    public Category(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("Name cannot be empty.", nameof(name));
         
        Name = name.Trim();
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
 
    // State change method
    public void UpdateDetails(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new ArgumentException("Name cannot be empty.", nameof(name));
         
        Name = name.Trim();
        UpdatedAt = DateTime.UtcNow;
    }
}
```
 
### 2. Repository Interface
Create a dedicated repository interface in the `Interfaces/` folder:
```csharp
// {P}-backend/src/{P}.Domain/Interfaces/ICategoryRepository.cs
using {P}.Domain.Common;
using {P}.Domain.Entities;
 
namespace {P}.Domain.Interfaces;
 
public interface ICategoryRepository : IRepository<Category>
{
    // Add custom query methods here if needed
}
```
'@
.Replace("{P}", $ProjectName).Replace("{Entities}", $allEntitiesStr)

Write-Guide "domain-guide.md" $domainGuideContent