using MyTelegram.Domain.Aggregates.Stars;
using MyTelegram.Domain.Events.Stars;
using MyTelegram.ReadModel.Interfaces;
using MongoDB.Bson.Serialization.Attributes;

namespace MyTelegram.ReadModel.Impl;

public class StarsReadModel : IStarsReadModel,
    IMongoDbReadModel,
    IAmReadModelFor<StarsAggregate, StarsId, StarsAccountCreatedEvent>,
    IAmReadModelFor<StarsAggregate, StarsId, StarsAddedEvent>,
    IAmReadModelFor<StarsAggregate, StarsId, StarsSpentEvent>,
    IAmReadModelFor<StarsAggregate, StarsId, StarsRefundedEvent>
{
    [BsonId]
    public string Id { get; set; }
    public long PeerId { get; set; }
    public long Balance { get; set; }
    public List<StarsTransaction> History { get; set; } = new();
    public long? Version { get; set; }

    public Task ApplyAsync(IReadModelContext context, IDomainEvent<StarsAggregate, StarsId, StarsAccountCreatedEvent> domainEvent, CancellationToken cancellationToken)
    {
        Console.WriteLine($"[StarsReadModel] Applying StarsAccountCreatedEvent. PeerId: {domainEvent.AggregateEvent.PeerId}, Balance: {domainEvent.AggregateEvent.Balance}");
        Id = domainEvent.AggregateIdentity.Value;
        PeerId = domainEvent.AggregateEvent.PeerId;
        Balance = domainEvent.AggregateEvent.Balance;
        Console.WriteLine($"[StarsReadModel] StarsAccountCreatedEvent applied. Id: {Id}, PeerId: {PeerId}, Balance: {Balance}");
        return Task.CompletedTask;
    }

    public Task ApplyAsync(IReadModelContext context, IDomainEvent<StarsAggregate, StarsId, StarsAddedEvent> domainEvent, CancellationToken cancellationToken)
    {
        Console.WriteLine($"[StarsReadModel] Applying StarsAddedEvent. PeerId: {PeerId}, OldBalance: {Balance}, NewBalance: {domainEvent.AggregateEvent.NewBalance}, Amount: {domainEvent.AggregateEvent.Amount}");
        Id = domainEvent.AggregateIdentity.Value;
        Balance = domainEvent.AggregateEvent.NewBalance;
        History.Add(new StarsTransaction
        {
            Id = domainEvent.AggregateEvent.TransactionId,
            Amount = domainEvent.AggregateEvent.Amount,
            Date = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
            TransactionId = domainEvent.AggregateEvent.TransactionId,
            Reason = domainEvent.AggregateEvent.Reason
        });
        Console.WriteLine($"[StarsReadModel] StarsAddedEvent applied. New balance: {Balance}, Transaction added to history");
        return Task.CompletedTask;
    }

    public Task ApplyAsync(IReadModelContext context, IDomainEvent<StarsAggregate, StarsId, StarsSpentEvent> domainEvent, CancellationToken cancellationToken)
    {
        Console.WriteLine($"[StarsReadModel] Applying StarsSpentEvent. PeerId: {PeerId}, OldBalance: {Balance}, NewBalance: {domainEvent.AggregateEvent.NewBalance}, Amount: {domainEvent.AggregateEvent.Amount}");
        Id = domainEvent.AggregateIdentity.Value;
        Balance = domainEvent.AggregateEvent.NewBalance;
        History.Add(new StarsTransaction
        {
            Id = domainEvent.AggregateEvent.TransactionId,
            Amount = -domainEvent.AggregateEvent.Amount,
            Date = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
            TransactionId = domainEvent.AggregateEvent.TransactionId,
            Reason = domainEvent.AggregateEvent.Reason
        });
        Console.WriteLine($"[StarsReadModel] StarsSpentEvent applied. New balance: {Balance}, Transaction added to history");
        return Task.CompletedTask;
    }

    public Task ApplyAsync(IReadModelContext context, IDomainEvent<StarsAggregate, StarsId, StarsRefundedEvent> domainEvent, CancellationToken cancellationToken)
    {
        Id = domainEvent.AggregateIdentity.Value;
        Balance = domainEvent.AggregateEvent.NewBalance;
        History.Add(new StarsTransaction
        {
            Id = domainEvent.AggregateEvent.RefundTransactionId,
            Amount = domainEvent.AggregateEvent.Amount,
            Date = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
            TransactionId = domainEvent.AggregateEvent.RefundTransactionId,
            Reason = $"Refund: {domainEvent.AggregateEvent.OriginalTransactionId}"
        });
        return Task.CompletedTask;
    }
}
