using FacebookService.Domain.Events;
using FacebookService.Domain.Exceptions;
using FacebookService.Domain.SeedWork;

namespace FacebookService.Domain.AggregatesModel.ConversationAggregate;

/// <summary>
/// EN: Conversation aggregate root managing the lifecycle of a customer conversation.
/// VI: Conversation aggregate root quản lý vòng đời của một cuộc hội thoại với khách hàng.
/// </summary>
public class Conversation : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _customerId;
    private string _pageId = null!;
    private ConversationStatus _status = null!;
    private string _channel = "FacebookMessenger";
    private string? _assignedAgentId;
    private DateTime? _lastMessageAt;
    private DateTime _createdAt;
    private List<Message> _messages = new();

    /// <summary>
    /// EN: Customer ID who owns this conversation.
    /// VI: ID khách hàng sở hữu cuộc hội thoại này.
    /// </summary>
    public Guid CustomerId => _customerId;

    /// <summary>
    /// EN: Facebook Page ID where conversation happens.
    /// VI: ID trang Facebook nơi cuộc hội thoại diễn ra.
    /// </summary>
    public string PageId => _pageId;

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

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

    /// <summary>
    /// EN: Channel type (FacebookMessenger). / VI: Loại kênh.
    /// </summary>
    public string Channel => _channel;

    /// <summary>
    /// EN: Assigned agent ID for human handoff.
    /// VI: ID agent được phân công cho handoff.
    /// </summary>
    public string? AssignedAgentId => _assignedAgentId;

    /// <summary>
    /// EN: Timestamp of last message. / VI: Thời gian tin nhắn cuối.
    /// </summary>
    public DateTime? LastMessageAt => _lastMessageAt;

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

    /// <summary>
    /// EN: All messages in this conversation.
    /// VI: Tất cả tin nhắn trong cuộc hội thoại này.
    /// </summary>
    public IReadOnlyCollection<Message> Messages => _messages.AsReadOnly();

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

    /// <summary>
    /// EN: Create a new conversation.
    /// VI: Tạo cuộc hội thoại mới.
    /// </summary>
    /// <param name="customerId">EN: Customer ID / VI: ID khách hàng</param>
    /// <param name="pageId">EN: Facebook Page ID / VI: ID trang Facebook</param>
    public Conversation(Guid customerId, string pageId) : this()
    {
        if (customerId == Guid.Empty)
            throw new FacebookDomainException("Customer ID cannot be empty");
        
        if (string.IsNullOrWhiteSpace(pageId))
            throw new FacebookDomainException("Page ID cannot be empty");

        Id = Guid.NewGuid();
        _customerId = customerId;
        _pageId = pageId;
        _status = ConversationStatus.Active;
        StatusId = ConversationStatus.Active.Id;
        _createdAt = DateTime.UtcNow;

        AddDomainEvent(new ConversationCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Add a message to the conversation.
    /// VI: Thêm tin nhắn vào cuộc hội thoại.
    /// </summary>
    /// <exception cref="FacebookDomainException">
    /// EN: Thrown when conversation is not active.
    /// VI: Ném ra khi cuộc hội thoại không hoạt động.
    /// </exception>
    public void AddMessage(Message message)
    {
        if (_status != ConversationStatus.Active)
            throw new FacebookDomainException("Cannot add messages to a closed or archived conversation");

        if (message == null)
            throw new FacebookDomainException("Message cannot be null");

        _messages.Add(message);
        _lastMessageAt = message.SentAt;

        AddDomainEvent(new MessageAddedDomainEvent(Id, message));
    }

    /// <summary>
    /// EN: Mark all messages as read.
    /// VI: Đánh dấu tất cả tin nhắn đã đọc.
    /// </summary>
    public void MarkAsRead()
    {
        // EN: Could add read receipt tracking here
        // VI: Có thể thêm theo dõi xác nhận đọc ở đây
    }

    /// <summary>
    /// EN: Assign conversation to a human agent.
    /// VI: Gán cuộc hội thoại cho một agent.
    /// </summary>
    /// <param name="agentId">EN: Agent ID / VI: ID agent</param>
    public void Assign(string agentId)
    {
        if (string.IsNullOrWhiteSpace(agentId))
            throw new FacebookDomainException("Agent ID cannot be empty");

        if (_status != ConversationStatus.Active)
            throw new FacebookDomainException("Cannot assign a closed or archived conversation");

        _assignedAgentId = agentId;
        AddDomainEvent(new ConversationAssignedDomainEvent(Id, agentId));
    }

    /// <summary>
    /// EN: Unassign the conversation from current agent.
    /// VI: Hủy gán cuộc hội thoại khỏi agent hiện tại.
    /// </summary>
    public void Unassign()
    {
        _assignedAgentId = null;
    }

    /// <summary>
    /// EN: Close the conversation.
    /// VI: Đóng cuộc hội thoại.
    /// </summary>
    public void Close()
    {
        if (_status == ConversationStatus.Closed)
            throw new FacebookDomainException("Conversation is already closed");

        if (_status == ConversationStatus.Archived)
            throw new FacebookDomainException("Cannot close an archived conversation");

        var previousStatus = _status;
        _status = ConversationStatus.Closed;
        StatusId = ConversationStatus.Closed.Id;

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

    /// <summary>
    /// EN: Reopen a closed conversation.
    /// VI: Mở lại cuộc hội thoại đã đóng.
    /// </summary>
    public void Reopen()
    {
        if (_status != ConversationStatus.Closed)
            throw new FacebookDomainException("Only closed conversations can be reopened");

        var previousStatus = _status;
        _status = ConversationStatus.Active;
        StatusId = ConversationStatus.Active.Id;

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

    /// <summary>
    /// EN: Archive the conversation.
    /// VI: Lưu trữ cuộc hội thoại.
    /// </summary>
    public void Archive()
    {
        if (_status == ConversationStatus.Archived)
            throw new FacebookDomainException("Conversation is already archived");

        var previousStatus = _status;
        _status = ConversationStatus.Archived;
        StatusId = ConversationStatus.Archived.Id;

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