using SocialService.Domain.Events;
using SocialService.Domain.Exceptions;
using SocialService.Domain.SeedWork;

namespace SocialService.Domain.AggregatesModel.RelationshipAggregate;

/// <summary>
/// EN: Aggregate root for managing relationships between users (friendship, following).
/// VI: Aggregate root để quản lý quan hệ giữa các users (kết bạn, theo dõi).
/// </summary>
public class Relationship : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _requesterId;
    private Guid _addresseeId;
    private RelationshipType _type = null!;
    private RelationshipStatus _status = null!;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    /// <summary>
    /// EN: ID of the user who initiated the relationship.
    /// VI: ID của user đã khởi tạo quan hệ.
    /// </summary>
    public Guid RequesterId => _requesterId;

    /// <summary>
    /// EN: ID of the user who received the relationship request.
    /// VI: ID của user nhận được yêu cầu quan hệ.
    /// </summary>
    public Guid AddresseeId => _addresseeId;

    /// <summary>
    /// EN: Type of relationship (Friendship, Following).
    /// VI: Loại quan hệ (Kết bạn, Theo dõi).
    /// </summary>
    public RelationshipType Type => _type;

    /// <summary>
    /// EN: Type ID for EF Core mapping.
    /// VI: ID type cho EF Core mapping.
    /// </summary>
    public int TypeId { get; private set; }

    /// <summary>
    /// EN: Current status of the relationship.
    /// VI: Trạng thái hiện tại của quan hệ.
    /// </summary>
    public RelationshipStatus 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 Relationship() { }

    /// <summary>
    /// EN: Create a new relationship (friend request or follow).
    /// VI: Tạo một quan hệ mới (yêu cầu kết bạn hoặc theo dõi).
    /// </summary>
    /// <param name="requesterId">EN: Requester user ID / VI: ID user gửi yêu cầu</param>
    /// <param name="addresseeId">EN: Addressee user ID / VI: ID user nhận yêu cầu</param>
    /// <param name="type">EN: Relationship type / VI: Loại quan hệ</param>
    public Relationship(Guid requesterId, Guid addresseeId, RelationshipType type) : this()
    {
        if (requesterId == Guid.Empty)
            throw new SocialDomainException("Requester ID cannot be empty");
        if (addresseeId == Guid.Empty)
            throw new SocialDomainException("Addressee ID cannot be empty");
        if (requesterId == addresseeId)
            throw new SocialDomainException("Cannot create relationship with yourself");

        Id = Guid.NewGuid();
        _requesterId = requesterId;
        _addresseeId = addresseeId;
        _type = type ?? throw new SocialDomainException("Relationship type is required");
        TypeId = type.Id;
        
        // EN: Following is auto-accepted, Friendship requires acceptance
        // VI: Following tự động chấp nhận, Friendship cần chấp nhận
        if (type == RelationshipType.Following)
        {
            _status = RelationshipStatus.Accepted;
            StatusId = RelationshipStatus.Accepted.Id;
            AddDomainEvent(new UserFollowedDomainEvent(this));
        }
        else
        {
            _status = RelationshipStatus.Pending;
            StatusId = RelationshipStatus.Pending.Id;
            AddDomainEvent(new FriendRequestSentDomainEvent(this));
        }
        
        _createdAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Accept the relationship request (for friendship).
    /// VI: Chấp nhận yêu cầu quan hệ (cho kết bạn).
    /// </summary>
    public void Accept()
    {
        if (_type != RelationshipType.Friendship)
            throw new SocialDomainException("Only friendship requests can be accepted");
        if (_status != RelationshipStatus.Pending)
            throw new SocialDomainException("Only pending requests can be accepted");

        var previousStatus = _status;
        _status = RelationshipStatus.Accepted;
        StatusId = RelationshipStatus.Accepted.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new FriendshipCreatedDomainEvent(this));
        AddDomainEvent(new RelationshipStatusChangedDomainEvent(Id, previousStatus, _status));
    }

    /// <summary>
    /// EN: Reject the relationship request (for friendship).
    /// VI: Từ chối yêu cầu quan hệ (cho kết bạn).
    /// </summary>
    public void Reject()
    {
        if (_type != RelationshipType.Friendship)
            throw new SocialDomainException("Only friendship requests can be rejected");
        if (_status != RelationshipStatus.Pending)
            throw new SocialDomainException("Only pending requests can be rejected");

        var previousStatus = _status;
        _status = RelationshipStatus.Rejected;
        StatusId = RelationshipStatus.Rejected.Id;
        _updatedAt = DateTime.UtcNow;

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

    /// <summary>
    /// EN: Cancel the relationship request (by requester).
    /// VI: Hủy yêu cầu quan hệ (bởi người gửi).
    /// </summary>
    public void Cancel()
    {
        if (_status != RelationshipStatus.Pending)
            throw new SocialDomainException("Only pending requests can be cancelled");

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

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

    /// <summary>
    /// EN: Remove the relationship (unfriend or unfollow).
    /// VI: Xóa quan hệ (hủy kết bạn hoặc hủy theo dõi).
    /// </summary>
    public void Remove()
    {
        if (_status != RelationshipStatus.Accepted)
            throw new SocialDomainException("Only accepted relationships can be removed");

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

        AddDomainEvent(new RelationshipRemovedDomainEvent(this));
        AddDomainEvent(new RelationshipStatusChangedDomainEvent(Id, previousStatus, _status));
    }
}
