using System;
using System.Collections.Generic;
using Knot.Shared.Kernel;
using MongoDB.Bson.Serialization.Attributes;
namespace Knot.Modules.Messaging.Domain;
///
/// Абстрактная база агрегата Сообщение.
///
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(TextMessage), typeof(MediaMessage), typeof(StoryMessage), typeof(PollMessage))]
public abstract class Message : AggregateRoot
{
// ================== Базовые поля ==================
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 _deletedFor = new();
public IReadOnlyCollection DeletedFor => _deletedFor.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));
}
}
}