using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Workflow.Domain.Common;

namespace Workflow.Infrastructure.Persistence.Interceptors;

public class AuditInterceptor : SaveChangesInterceptor
{
    private readonly ICurrentUserContext _currentUserContext;

    public AuditInterceptor(ICurrentUserContext currentUserContext)
    {
        _currentUserContext = currentUserContext;
    }

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

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

    private void ApplyAuditFields(DbContext? context)
    {
        if (context is null) return;

        var userId = _currentUserContext.GetUserId();
        var ipAddress = _currentUserContext.GetIPAddress();
        var now = DateTime.UtcNow;

        foreach (var entry in context.ChangeTracker.Entries())
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    SetCreatedFields(entry, userId, now);
                    SetUpdatedFields(entry, userId, now);
                    SetOperatorIP(entry, ipAddress);
                    break;
                case EntityState.Modified:
                    SetUpdatedFields(entry, userId, now);
                    SetOperatorIP(entry, ipAddress);
                    break;
                case EntityState.Deleted:
                    HandleSoftDelete(entry, userId, now, ipAddress);
                    break;
            }
        }
    }

    private static void SetCreatedFields(EntityEntry entry, Guid userId, DateTime now)
    {
        if (entry.Entity is IAuditable auditable)
        {
            auditable.CreatedBy = userId;
            auditable.CreatedAt = now;
        }
    }

    private static void SetUpdatedFields(EntityEntry entry, Guid userId, DateTime now)
    {
        if (entry.Entity is IAuditable auditable)
        {
            auditable.UpdatedBy = userId;
            auditable.UpdatedAt = now;
        }
    }

    private static void SetOperatorIP(EntityEntry entry, string? ipAddress)
    {
        if (entry.Entity is IHasOperatorIP hasIp)
        {
            hasIp.OperatorIP = ipAddress;
        }
    }

    private static void HandleSoftDelete(EntityEntry entry, Guid userId, DateTime now, string? ipAddress)
    {
        if (entry.Entity is not ISoftDelete softDeletable) return;

        // 将删除操作转为软删除：设置 IsDeleted = true，修改状态为 Modified
        entry.State = EntityState.Modified;
        softDeletable.IsDeleted = true;

        // 更新审计字段
        if (entry.Entity is IAuditable auditable)
        {
            auditable.UpdatedBy = userId;
            auditable.UpdatedAt = now;
        }

        if (entry.Entity is IHasOperatorIP hasIp)
        {
            hasIp.OperatorIP = ipAddress;
        }
    }
}
