using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using MilitaryTrainingManagement.Models.Entities;
using MilitaryTrainingManagement.Services.Implementations;

namespace MilitaryTrainingManagement.Data;

/// <summary>
/// EF Core 审计拦截器 - 自动记录数据变更
/// </summary>
public class AuditInterceptor : SaveChangesInterceptor
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuditInterceptor(IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor)
    {
        _serviceProvider = serviceProvider;
        _httpContextAccessor = httpContextAccessor;
    }

    public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData,
        InterceptionResult<int> result,
        CancellationToken cancellationToken = default)
    {
        if (eventData.Context is ApplicationDbContext context)
        {
            await ProcessAuditEntriesAsync(context);
        }

        return await base.SavingChangesAsync(eventData, result, cancellationToken);
    }

    private Task ProcessAuditEntriesAsync(ApplicationDbContext context)
    {
        var auditEntries = new List<AuditEntry>();
        var httpContext = _httpContextAccessor.HttpContext;

        // 获取当前用户信息
        int? userId = null;
        int? organizationalUnitId = null;
        string? ipAddress = null;
        string? userAgent = null;
        string? requestPath = null;

        if (httpContext != null)
        {
            var userIdClaim = httpContext.User.FindFirst("userId")?.Value;
            if (int.TryParse(userIdClaim, out var parsedUserId))
                userId = parsedUserId;

            var unitIdClaim = httpContext.User.FindFirst("unitId")?.Value;
            if (int.TryParse(unitIdClaim, out var parsedUnitId))
                organizationalUnitId = parsedUnitId;

            ipAddress = GetClientIpAddress(httpContext);
            userAgent = httpContext.Request.Headers.UserAgent.ToString();
            requestPath = httpContext.Request.Path.ToString();
        }

        foreach (var entry in context.ChangeTracker.Entries())
        {
            // 跳过审计日志本身，避免无限循环
            if (entry.Entity is AuditLog)
                continue;

            // 只审计特定的实体类型
            if (!ShouldAudit(entry.Entity.GetType()))
                continue;

            var auditEntry = new AuditEntry
            {
                EntityType = entry.Entity.GetType().Name,
                UserId = userId,
                OrganizationalUnitId = organizationalUnitId,
                IpAddress = ipAddress,
                UserAgent = userAgent,
                RequestPath = requestPath,
                Timestamp = DateTime.UtcNow
            };

            switch (entry.State)
            {
                case EntityState.Added:
                    auditEntry.Action = AuditActions.Create;
                    auditEntry.NewValues = SerializeProperties(entry.CurrentValues);
                    // EntityId 将在保存后设置
                    break;

                case EntityState.Modified:
                    auditEntry.Action = AuditActions.Update;
                    auditEntry.OldValues = SerializeProperties(entry.OriginalValues);
                    auditEntry.NewValues = SerializeProperties(entry.CurrentValues);
                    auditEntry.ChangedFields = GetChangedProperties(entry);
                    auditEntry.EntityId = GetEntityId(entry);
                    break;

                case EntityState.Deleted:
                    auditEntry.Action = AuditActions.Delete;
                    auditEntry.OldValues = SerializeProperties(entry.OriginalValues);
                    auditEntry.EntityId = GetEntityId(entry);
                    break;

                default:
                    continue;
            }

            auditEntries.Add(auditEntry);
        }

        // 添加审计日志到上下文
        foreach (var auditEntry in auditEntries)
        {
            var auditLog = new AuditLog
            {
                EntityType = auditEntry.EntityType,
                EntityId = auditEntry.EntityId,
                Action = auditEntry.Action,
                Description = GetActionDescription(auditEntry.Action, auditEntry.EntityType),
                OldValues = auditEntry.OldValues,
                NewValues = auditEntry.NewValues,
                ChangedFields = auditEntry.ChangedFields,
                UserId = auditEntry.UserId,
                OrganizationalUnitId = auditEntry.OrganizationalUnitId,
                IpAddress = auditEntry.IpAddress,
                UserAgent = auditEntry.UserAgent,
                RequestPath = auditEntry.RequestPath,
                Timestamp = auditEntry.Timestamp,
                IsSuccess = true
            };

            context.AuditLogs.Add(auditLog);
        }
        
        return Task.CompletedTask;
    }


    private static bool ShouldAudit(Type entityType)
    {
        // 定义需要审计的实体类型
        var auditableTypes = new[]
        {
            typeof(MaterialAllocation),
            typeof(AllocationDistribution),
            typeof(Personnel),
            typeof(OrganizationalUnit),
            typeof(UserAccount),
            typeof(ApprovalRequest),
            typeof(PersonnelApprovalHistory)
        };

        return auditableTypes.Contains(entityType);
    }

    private static int GetEntityId(Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entry)
    {
        var idProperty = entry.Properties.FirstOrDefault(p => p.Metadata.Name == "Id");
        if (idProperty?.CurrentValue is int id)
            return id;
        return 0;
    }

    private static string? SerializeProperties(Microsoft.EntityFrameworkCore.ChangeTracking.PropertyValues? values)
    {
        if (values == null)
            return null;

        var dict = new Dictionary<string, object?>();
        foreach (var property in values.Properties)
        {
            // 跳过导航属性和复杂类型
            if (property.ClrType.IsClass && property.ClrType != typeof(string))
                continue;

            var value = values[property];
            dict[property.Name] = value;
        }

        return JsonSerializer.Serialize(dict, new JsonSerializerOptions
        {
            WriteIndented = false,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
    }

    private static string? GetChangedProperties(Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entry)
    {
        var changedProperties = new List<string>();

        foreach (var property in entry.Properties)
        {
            if (property.IsModified)
            {
                changedProperties.Add(property.Metadata.Name);
            }
        }

        return changedProperties.Count > 0
            ? JsonSerializer.Serialize(changedProperties)
            : null;
    }

    private static string? GetClientIpAddress(HttpContext httpContext)
    {
        // 尝试从 X-Forwarded-For 头获取（用于代理/负载均衡器后面的情况）
        var forwardedFor = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
        if (!string.IsNullOrEmpty(forwardedFor))
        {
            return forwardedFor.Split(',').First().Trim();
        }

        // 否则使用远程IP地址
        return httpContext.Connection.RemoteIpAddress?.ToString();
    }

    private static string GetActionDescription(string action, string entityType)
    {
        var entityDisplayName = entityType switch
        {
            "MaterialAllocation" => "物资配额",
            "AllocationDistribution" => "配额分配",
            "Personnel" => "人员",
            "OrganizationalUnit" => "组织单位",
            "UserAccount" => "用户账户",
            "ApprovalRequest" => "审批请求",
            "PersonnelApprovalHistory" => "人员审批历史",
            _ => entityType
        };

        return action switch
        {
            AuditActions.Create => $"创建{entityDisplayName}记录",
            AuditActions.Update => $"更新{entityDisplayName}记录",
            AuditActions.Delete => $"删除{entityDisplayName}记录",
            _ => $"{action}{entityDisplayName}记录"
        };
    }
}

/// <summary>
/// 审计条目（临时存储）
/// </summary>
internal class AuditEntry
{
    public string EntityType { get; set; } = string.Empty;
    public int EntityId { get; set; }
    public string Action { get; set; } = string.Empty;
    public string? OldValues { get; set; }
    public string? NewValues { get; set; }
    public string? ChangedFields { get; set; }
    public int? UserId { get; set; }
    public int? OrganizationalUnitId { get; set; }
    public string? IpAddress { get; set; }
    public string? UserAgent { get; set; }
    public string? RequestPath { get; set; }
    public DateTime Timestamp { get; set; }
}
