using MktZaloService.Domain.Enums;
using MktZaloService.Domain.Events;
using MktZaloService.Domain.Exceptions;
using MktZaloService.Domain.SeedWork;

namespace MktZaloService.Domain.AggregatesModel.ConversationAggregate;

/// <summary>
/// EN: Aggregate root for managing conversations and messages.
/// VI: Aggregate root để quản lý cuộc hội thoại và tin nhắn.
/// </summary>
public class Conversation : Entity, IAggregateRoot
{
    private readonly List<Message> _messages = new();

    /// <summary>
    /// EN: Zalo user ID of the customer.
    /// VI: ID người dùng Zalo của khách hàng.
    /// </summary>
    public string ZaloUserId { get; private set; } = string.Empty;

    /// <summary>
    /// EN: ID of the customer in our system.
    /// VI: ID khách hàng trong hệ thống của chúng ta.
    /// </summary>
    public Guid CustomerId { get; private set; }

    /// <summary>
    /// EN: Current status of the conversation.
    /// VI: Trạng thái hiện tại của cuộc hội thoại.
    /// </summary>
    public ConversationStatus Status { get; private set; }

    /// <summary>
    /// EN: When the conversation started.
    /// VI: Thời điểm cuộc hội thoại bắt đầu.
    /// </summary>
    public DateTime StartedAt { get; private set; }

    /// <summary>
    /// EN: When the conversation ended (if closed).
    /// VI: Thời điểm cuộc hội thoại kết thúc (nếu đã đóng).
    /// </summary>
    public DateTime? EndedAt { get; private set; }

    /// <summary>
    /// EN: Total message count in this conversation.
    /// VI: Tổng số tin nhắn trong cuộc hội thoại này.
    /// </summary>
    public int MessageCount { get; private set; }

    /// <summary>
    /// EN: Last message preview text.
    /// VI: Nội dung xem trước tin nhắn cuối.
    /// </summary>
    public string? LastMessagePreview { get; private set; }

    /// <summary>
    /// EN: Timestamp of the last message.
    /// VI: Thời điểm tin nhắn cuối cùng.
    /// </summary>
    public DateTime? LastMessageAt { get; private set; }

    /// <summary>
    /// EN: Read-only collection of messages.
    /// VI: Danh sách tin nhắn chỉ đọc.
    /// </summary>
    public IReadOnlyCollection<Message> Messages => _messages.AsReadOnly();

    /// <summary>
    /// EN: Audit field: Created timestamp.
    /// VI: Trường audit: Thời điểm tạo.
    /// </summary>
    public DateTime CreatedAt { get; private set; }

    /// <summary>
    /// EN: Audit field: Last updated timestamp.
    /// VI: Trường audit: Thời điểm cập nhật cuối.
    /// </summary>
    public DateTime UpdatedAt { get; private set; }

    /// <summary>
    /// EN: Required by EF Core.
    /// VI: Yêu cầu bởi EF Core.
    /// </summary>
    protected Conversation() { }

    /// <summary>
    /// EN: Create a new conversation.
    /// VI: Tạo cuộc hội thoại mới.
    /// </summary>
    public Conversation(string zaloUserId, Guid customerId)
    {
        Id = Guid.NewGuid();
        ZaloUserId = zaloUserId ?? throw new ArgumentNullException(nameof(zaloUserId));
        CustomerId = customerId;
        Status = ConversationStatus.Active;
        StartedAt = DateTime.UtcNow;
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
        MessageCount = 0;

        AddDomainEvent(new ConversationStartedDomainEvent(Id, CustomerId, ZaloUserId));
    }

    /// <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="ConversationClosedException">
    /// EN: Thrown when trying to add message to closed conversation.
    /// VI: Ném khi cố gắng thêm tin nhắn vào cuộc hội thoại đã đóng.
    /// </exception>
    public Message AddMessage(
        MessageType type,
        string content,
        MessageDirection direction,
        bool isFromBot,
        string? zaloMessageId = null)
    {
        if (Status == ConversationStatus.Closed)
        {
            throw new ConversationClosedException(Id);
        }

        var message = new Message(type, content, direction, isFromBot, zaloMessageId);
        _messages.Add(message);

        MessageCount++;
        LastMessagePreview = content.Length > 100 ? content[..100] + "..." : content;
        LastMessageAt = message.SentAt;
        UpdatedAt = DateTime.UtcNow;

        AddDomainEvent(new MessageReceivedDomainEvent(Id, message.Id, content, isFromBot));

        return message;
    }

    /// <summary>
    /// EN: Close the conversation.
    /// VI: Đóng cuộc hội thoại.
    /// </summary>
    public void Close()
    {
        if (Status == ConversationStatus.Closed)
        {
            return; // Idempotent
        }

        Status = ConversationStatus.Closed;
        EndedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;

        AddDomainEvent(new ConversationClosedDomainEvent(Id));
    }

    /// <summary>
    /// EN: Reopen a closed conversation.
    /// VI: Mở lại cuộc hội thoại đã đóng.
    /// </summary>
    public void Reopen()
    {
        if (Status == ConversationStatus.Active)
        {
            return; // Idempotent
        }

        Status = ConversationStatus.Active;
        EndedAt = null;
        UpdatedAt = DateTime.UtcNow;
    }
}
