using MktXService.Domain.Events;
using MktXService.Domain.Exceptions;
using MktXService.Domain.SeedWork;

namespace MktXService.Domain.AggregatesModel.SampleAggregate;

/// <summary>
/// EN: Sample aggregate root demonstrating DDD patterns.
/// VI: Sample aggregate root minh họa các pattern DDD.
/// </summary>
public class Sample : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private string _name = null!;
    private string? _description;
    private SampleStatus _status = null!;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    /// <summary>
    /// EN: Sample name (required).
    /// VI: Tên sample (bắt buộc).
    /// </summary>
    public string Name => _name;

    /// <summary>
    /// EN: Optional description.
    /// VI: Mô tả tùy chọn.
    /// </summary>
    public string? Description => _description;

    /// <summary>
    /// EN: Current status.
    /// VI: Trạng thái hiện tại.
    /// </summary>
    public SampleStatus Status => _status;

    /// <summary>
    /// EN: Status ID for EF Core mapping.
    /// VI: ID trạng thái cho EF Core mapping.
    /// </summary>
    public int StatusId { get; private set; }

    /// <summary>
    /// EN: Creation timestamp.
    /// VI: Thời gian tạo.
    /// </summary>
    public DateTime CreatedAt => _createdAt;

    /// <summary>
    /// EN: Last update timestamp.
    /// VI: Thời gian cập nhật cuối.
    /// </summary>
    public DateTime? UpdatedAt => _updatedAt;

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    protected Sample()
    {
    }

    /// <summary>
    /// EN: Create a new Sample with required information.
    /// VI: Tạo một Sample mới với thông tin bắt buộc.
    /// </summary>
    /// <param name="name">EN: Sample name / VI: Tên sample</param>
    /// <param name="description">EN: Optional description / VI: Mô tả tùy chọn</param>
    public Sample(string name, string? description = null) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new SampleDomainException("Sample name cannot be empty");

        Id = Guid.NewGuid();
        _name = name;
        _description = description;
        _status = SampleStatus.Draft;
        StatusId = SampleStatus.Draft.Id;
        _createdAt = DateTime.UtcNow;

        // EN: Add domain event for creation
        // VI: Thêm domain event cho việc tạo
        AddDomainEvent(new SampleCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Update sample information.
    /// VI: Cập nhật thông tin sample.
    /// </summary>
    public void Update(string name, string? description)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new SampleDomainException("Sample name cannot be empty");

        if (_status == SampleStatus.Cancelled)
            throw new SampleDomainException("Cannot update a cancelled sample");

        _name = name;
        _description = description;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Activate the sample.
    /// VI: Kích hoạt sample.
    /// </summary>
    public void Activate()
    {
        if (_status != SampleStatus.Draft)
            throw new SampleDomainException("Only draft samples can be activated");

        var previousStatus = _status;
        _status = SampleStatus.Active;
        StatusId = SampleStatus.Active.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status));
    }

    /// <summary>
    /// EN: Complete the sample.
    /// VI: Hoàn thành sample.
    /// </summary>
    public void Complete()
    {
        if (_status != SampleStatus.Active)
            throw new SampleDomainException("Only active samples can be completed");

        var previousStatus = _status;
        _status = SampleStatus.Completed;
        StatusId = SampleStatus.Completed.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status));
    }

    /// <summary>
    /// EN: Cancel the sample.
    /// VI: Hủy sample.
    /// </summary>
    public void Cancel()
    {
        if (_status == SampleStatus.Completed)
            throw new SampleDomainException("Cannot cancel a completed sample");

        if (_status == SampleStatus.Cancelled)
            throw new SampleDomainException("Sample is already cancelled");

        var previousStatus = _status;
        _status = SampleStatus.Cancelled;
        StatusId = SampleStatus.Cancelled.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status));
    }
}
