using System;
using System.Collections.Generic;
using System.Linq;
using MongoDB.Bson.Serialization.Attributes;

namespace Knot.Modules.Messaging.Domain;

[BsonDiscriminator("PollMessage")]
public class PollMessage : Message
{
    public override string Type => "poll";
    public override string? Content { get; protected set; } // Вопрос опроса

    public bool IsAnonymous { get; protected set; }
    public bool AllowMultipleAnswers { get; protected set; }
    public bool IsClosed { get; protected set; }
    public DateTime? ExpiresAt { get; protected set; }

    private List<PollOption> _options = new();
    public IReadOnlyCollection<PollOption> Options => _options.AsReadOnly();

    private List<PollVote> _votes = new();
    public IReadOnlyCollection<PollVote> Votes => _votes.AsReadOnly();

    // Инфраструктурный конструктор
    private PollMessage() : base() { }

    public PollMessage(
        Guid id,
        Guid chatId,
        Guid senderId,
        string question,
        List<string> options,
        bool isAnonymous,
        bool allowMultipleAnswers,
        DateTime? expiresAt,
        Guid? replyToId,
        Guid? forwardedFromId,
        DateTime createdAt,
        bool isImported)
        : base(id, chatId, senderId, replyToId, forwardedFromId, createdAt, isImported)
    {
        Content = question;
        IsAnonymous = isAnonymous;
        AllowMultipleAnswers = allowMultipleAnswers;
        ExpiresAt = expiresAt;
        IsClosed = false;

        foreach (var optionText in options)
        {
            _options.Add(new PollOption(Guid.NewGuid(), Id, optionText));
        }

        if (!isImported)
        {
            // Можно добавить специфичное событие для опроса
            // RaiseDomainEvent(new PollCreatedDomainEvent(Id, ChatId, SenderId, question));
        }
    }

    public void Vote(Guid userId, List<Guid> optionIds)
    {
        if (IsClosed) throw new InvalidOperationException("Poll is closed");
        if (ExpiresAt.HasValue && DateTime.UtcNow > ExpiresAt.Value)
        {
            Close();
            throw new InvalidOperationException("Poll has expired");
        }

        if (optionIds == null || !optionIds.Any()) throw new ArgumentException("At least one option must be selected");
        if (!AllowMultipleAnswers && optionIds.Count > 1) throw new ArgumentException("Multiple answers are not allowed");

        // Проверяем существование опций
        foreach (var oid in optionIds)
        {
            if (!_options.Any(o => o.Id == oid)) throw new ArgumentException($"Option {oid} not found");
        }

        // Удаляем старые голоса пользователя
        _votes.RemoveAll(v => v.UserId == userId);

        // Добавляем новые голоса
        foreach (var oid in optionIds)
        {
            _votes.Add(new PollVote(Id, userId, oid, DateTime.UtcNow));
        }

        // Обновляем статистику в опциях
        RecalculateResults();
    }

    public void Close()
    {
        IsClosed = true;
    }

    private void RecalculateResults()
    {
        int totalVotesCount = _votes.Select(v => v.UserId).Distinct().Count();
        
        foreach (var option in _options)
        {
            int optionVotes = _votes.Count(v => v.OptionId == option.Id);
            double percentage = totalVotesCount > 0 ? (double)optionVotes / totalVotesCount * 100 : 0;
            option.UpdateResults(optionVotes, (int)Math.Round(percentage));
        }
    }

    public override void Delete()
    {
        // При удалении опроса можно очистить голоса или оставить для истории (зависит от политики)
        base.Delete();
    }
}
