using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using ROLAC.API.Entities.Base;
using ROLAC.API.Services.Logging;

namespace ROLAC.API.Data.Interceptors;

public class AuditSaveChangesInterceptor : SaveChangesInterceptor
{
    private readonly CurrentUserAccessor _currentUser;

    public AuditSaveChangesInterceptor(CurrentUserAccessor currentUser) => _currentUser = currentUser;

    public override InterceptionResult<int> SavingChanges(
        DbContextEventData eventData, InterceptionResult<int> result)
    {
        Stamp(eventData.Context);
        return base.SavingChanges(eventData, result);
    }

    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData, InterceptionResult<int> result,
        CancellationToken cancellationToken = default)
    {
        Stamp(eventData.Context);
        return base.SavingChangesAsync(eventData, result, cancellationToken);
    }

    private void Stamp(DbContext? db)
    {
        if (db is null) return;

        var userId = _currentUser.UserIdOrSystem;
        var now = DateTimeOffset.UtcNow;

        foreach (var entry in db.ChangeTracker.Entries())
        {
            if (entry.Entity is not AuditableEntity audit) continue;

            if (entry.State == EntityState.Added)
            {
                audit.CreatedAt = now;
                audit.CreatedBy = userId;
                audit.UpdatedAt = now;
                audit.UpdatedBy = userId;
            }
            else if (entry.State == EntityState.Modified)
            {
                audit.UpdatedAt = now;
                audit.UpdatedBy = userId;
            }
        }
    }
}
