using ColaFlow.Domain.Common;
using ColaFlow.Domain.Events;
using ColaFlow.Domain.Exceptions;
using ColaFlow.Domain.ValueObjects;

namespace ColaFlow.Domain.Aggregates.ProjectAggregate;

/// <summary>
/// Project Aggregate Root
/// Enforces consistency boundary for Project -> Epic -> Story -> Task hierarchy
/// </summary>
public class Project : AggregateRoot
{
    public new ProjectId Id { get; private set; }
    public string Name { get; private set; }
    public string Description { get; private set; }
    public ProjectKey Key { get; private set; }
    public ProjectStatus Status { get; private set; }
    public UserId OwnerId { get; private set; }

    private readonly List<Epic> _epics = new();
    public IReadOnlyCollection<Epic> Epics => _epics.AsReadOnly();

    public DateTime CreatedAt { get; private set; }
    public DateTime? UpdatedAt { get; private set; }

    // EF Core constructor
    private Project()
    {
        Id = null!;
        Name = null!;
        Description = null!;
        Key = null!;
        Status = null!;
        OwnerId = null!;
    }

    // Factory method
    public static Project Create(string name, string description, string key, UserId ownerId)
    {
        // Validation
        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("Project name cannot be empty");

        if (name.Length > 200)
            throw new DomainException("Project name cannot exceed 200 characters");

        var project = new Project
        {
            Id = ProjectId.Create(),
            Name = name,
            Description = description ?? string.Empty,
            Key = ProjectKey.Create(key),
            Status = ProjectStatus.Active,
            OwnerId = ownerId,
            CreatedAt = DateTime.UtcNow
        };

        // Raise domain event
        project.AddDomainEvent(new ProjectCreatedEvent(project.Id, project.Name, ownerId));

        return project;
    }

    // Business methods
    public void UpdateDetails(string name, string description)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("Project name cannot be empty");

        if (name.Length > 200)
            throw new DomainException("Project name cannot exceed 200 characters");

        Name = name;
        Description = description ?? string.Empty;
        UpdatedAt = DateTime.UtcNow;

        AddDomainEvent(new ProjectUpdatedEvent(Id, Name, Description));
    }

    public Epic CreateEpic(string name, string description, UserId createdBy)
    {
        if (Status == ProjectStatus.Archived)
            throw new DomainException("Cannot create epic in an archived project");

        var epic = Epic.Create(name, description, this.Id, createdBy);
        _epics.Add(epic);

        AddDomainEvent(new EpicCreatedEvent(epic.Id, epic.Name, this.Id));

        return epic;
    }

    public void Archive()
    {
        if (Status == ProjectStatus.Archived)
            throw new DomainException("Project is already archived");

        Status = ProjectStatus.Archived;
        UpdatedAt = DateTime.UtcNow;

        AddDomainEvent(new ProjectArchivedEvent(Id));
    }

    public void Activate()
    {
        if (Status == ProjectStatus.Active)
            throw new DomainException("Project is already active");

        Status = ProjectStatus.Active;
        UpdatedAt = DateTime.UtcNow;
    }
}
