using System.Diagnostics;
using EventFlow.Aggregates;
using EventFlow.Core;
using EventFlow.Subscribers;

namespace Books.Api.Logging;

public class SubscribeAsynchronousToDecorator<TAggregate, TIdentity, TEvent>(
    ISubscribeAsynchronousTo<TAggregate, TIdentity, TEvent> inner,
    ILogger<SubscribeAsynchronousToDecorator<TAggregate, TIdentity, TEvent>> logger)
    : ISubscribeAsynchronousTo<TAggregate, TIdentity, TEvent>
    where TAggregate : IAggregateRoot<TIdentity>
    where TIdentity : IIdentity
    where TEvent : IAggregateEvent<TAggregate, TIdentity>
{
    public async Task HandleAsync(
        IDomainEvent<TAggregate, TIdentity, TEvent> domainEvent,
        CancellationToken cancellationToken)
    {
        var eventName = typeof(TEvent).Name;
        var handlerName = inner.GetType().Name;
        var aggregateId = domainEvent.AggregateIdentity.Value;

        logger.LogDebug(
            "Handling {EventName} for {AggregateId} with {HandlerName}",
            eventName, aggregateId, handlerName);

        var stopwatch = Stopwatch.StartNew();

        try
        {
            await inner.HandleAsync(domainEvent, cancellationToken);

            stopwatch.Stop();
            logger.LogInformation(
                "Handled {EventName} for {AggregateId} with {HandlerName} in {ElapsedMs}ms",
                eventName, aggregateId, handlerName, stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            logger.LogError(ex,
                "Failed to handle {EventName} for {AggregateId} with {HandlerName} after {ElapsedMs}ms",
                eventName, aggregateId, handlerName, stopwatch.ElapsedMilliseconds);
            throw;
        }
    }
}
