using ColaFlow.Shared.Kernel.Common;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;

using ColaFlow.Modules.ProjectManagement.Domain.Events;
namespace ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;

/// <summary>
/// Story Entity (part of Project aggregate)
/// </summary>
public class Story : Entity
{
    public new StoryId Id { get; private set; }
    public TenantId TenantId { get; private set; }
    public string Title { get; private set; }
    public string Description { get; private set; }
    public EpicId EpicId { get; private set; }
    public WorkItemStatus Status { get; private set; }
    public TaskPriority Priority { get; private set; }
    public decimal? EstimatedHours { get; private set; }
    public decimal? ActualHours { get; private set; }
    public UserId? AssigneeId { get; private set; }

    private readonly List<WorkTask> _tasks = new();
    public IReadOnlyCollection<WorkTask> Tasks => _tasks.AsReadOnly();

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

    // EF Core constructor
    private Story()
    {
        Id = null!;
        TenantId = null!;
        Title = null!;
        Description = null!;
        EpicId = null!;
        Status = null!;
        Priority = null!;
        CreatedBy = null!;
    }

    public static Story Create(TenantId tenantId, string title, string description, EpicId epicId, TaskPriority priority, UserId createdBy)
    {
        if (string.IsNullOrWhiteSpace(title))
            throw new DomainException("Story title cannot be empty");

        if (title.Length > 200)
            throw new DomainException("Story title cannot exceed 200 characters");

        return new Story
        {
            Id = StoryId.Create(),
            TenantId = tenantId,
            Title = title,
            Description = description ?? string.Empty,
            EpicId = epicId,
            Status = WorkItemStatus.ToDo,
            Priority = priority,
            CreatedAt = DateTime.UtcNow,
            CreatedBy = createdBy
        };
    }

    public WorkTask CreateTask(string title, string description, TaskPriority priority, UserId createdBy)
    {
        var task = WorkTask.Create(this.TenantId, title, description, this.Id, priority, createdBy);
        _tasks.Add(task);
        return task;
    }

    public void RemoveTask(TaskId taskId)
    {
        var task = _tasks.FirstOrDefault(t => t.Id == taskId);
        if (task == null)
            throw new DomainException($"Task with ID {taskId.Value} not found in story");

        _tasks.Remove(task);
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdateDetails(string title, string description)
    {
        if (string.IsNullOrWhiteSpace(title))
            throw new DomainException("Story title cannot be empty");

        if (title.Length > 200)
            throw new DomainException("Story title cannot exceed 200 characters");

        Title = title;
        Description = description ?? string.Empty;
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdateStatus(WorkItemStatus newStatus)
    {
        Status = newStatus;
        UpdatedAt = DateTime.UtcNow;
    }

    public void AssignTo(UserId assigneeId)
    {
        AssigneeId = assigneeId;
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdateEstimate(decimal hours)
    {
        if (hours < 0)
            throw new DomainException("Estimated hours cannot be negative");

        EstimatedHours = hours;
        UpdatedAt = DateTime.UtcNow;
    }

    public void LogActualHours(decimal hours)
    {
        if (hours < 0)
            throw new DomainException("Actual hours cannot be negative");

        ActualHours = hours;
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdatePriority(TaskPriority newPriority)
    {
        Priority = newPriority;
        UpdatedAt = DateTime.UtcNow;
    }
}
