using System;
using System.Collections.Generic;
using Knot.Shared.Kernel;

using MongoDB.Bson.Serialization.Attributes;

namespace Knot.Modules.Messaging.Domain;

/// <summary>
/// Абстрактная база агрегата Сообщение.
/// </summary>
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(TextMessage), typeof(MediaMessage), typeof(StoryMessage), typeof(PollMessage))]
public abstract class Message : AggregateRoot<Guid>
{
    // ================== Базовые поля ==================
    public Guid ChatId { get; protected set; }
    public Guid SenderId { get; protected set; }
    public DateTime CreatedAt { get; protected set; }
    public long SequenceId { get; protected set; }

    public void SetSequenceId(long sequenceId)
    {
        SequenceId = sequenceId;
    }
    // ================== Опциональные метаданные (общего назначения) ==================
    public Guid? ReplyToId { get; protected set; }
    public Guid? ForwardedFromId { get; protected set; }

    // ================== Флаги ==================
    public MessageState State { get; protected set; }

    // ================== Абстрактные / Виртуальные свойства ==================
    public abstract string Type { get; }
    public abstract string? Content { get; protected set; }

    public bool IsEdited => HasState(MessageState.IsEdited);
    public bool IsDeleted => HasState(MessageState.IsDeleted);
    public bool IsDeletedForUser(Guid userId) => _deletedFor.Exists(d => d.UserId == userId);

    // ================== Связанные коллекции (общего назначения) ==================
    protected List<DeletedMessage> _deletedFor = new();
    public IReadOnlyCollection<DeletedMessage> DeletedFor => _deletedFor.AsReadOnly();

    // ================== Прочитано ==================
    protected List<Guid> _readByUsers = new();
    public IReadOnlyCollection<Guid> ReadByUsers => _readByUsers.AsReadOnly();

    // ================== Инфраструктурный конструктор EF ==================
    protected Message() : base(Guid.Empty) { }

    protected Message(
        Guid id,
        Guid chatId,
        Guid senderId,
        Guid? replyToId,
        Guid? forwardedFromId,
        DateTime createdAt,
        bool isImported) : base(id)
    {
        ChatId = chatId;
        SenderId = senderId;
        ReplyToId = replyToId;
        ForwardedFromId = forwardedFromId;
        CreatedAt = createdAt;

        if (isImported) AddState(MessageState.IsImported);
    }

    // ================== Управление Состоянием ==================
    public void AddState(MessageState state) => State |= state;
    public void RemoveState(MessageState state) => State &= ~state;
    public bool HasState(MessageState state) => (State & state) == state;

    // ================== Общие операции ==================
    public virtual void Delete()
    {
        AddState(MessageState.IsDeleted);
        RaiseDomainEvent(new MessageDeletedDomainEvent(Id, ChatId));
    }

    public virtual void Edit(string newContent)
    {
        Content = newContent;
        AddState(MessageState.IsEdited);
        RaiseDomainEvent(new MessageEditedDomainEvent(Id, ChatId, newContent));
    }

    public void DeleteForUser(Guid userId)
    {
        if (!_deletedFor.Exists(x => x.UserId == userId))
        {
            _deletedFor.Add(new DeletedMessage(Id, userId));
        }
    }

    public void MarkAsRead(Guid userId)
    {
        if (!_readByUsers.Contains(userId))
        {
            _readByUsers.Add(userId);
        }
    }

    public bool IsReadBy(Guid userId) => _readByUsers.Contains(userId);
}


