using System.Data;
using KArtSell.BuildingBlocks.Time;
using Microsoft.Extensions.Logging;

namespace KArtSell.Modules.ModelOperations.Compliance;

/// <summary>
/// Command to log an audit event.
/// </summary>
public class LogAuditEventCommand
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public string EventType { get; set; } = string.Empty;
    public string EntityType { get; set; } = string.Empty;
    public Guid EntityId { get; set; }
    public string ActorEmail { get; set; } = string.Empty;
    public string? ActorRole { get; set; }
    public DateTime EventAt { get; set; }
    public string Result { get; set; } = "SUCCESS";
    public string? ErrorMessage { get; set; }
    public Dictionary<string, object>? Details { get; set; }
    public string[]? EvidenceLinks { get; set; }
    public string? IpAddress { get; set; }
    public string? UserAgent { get; set; }
    public Guid CorrelationId { get; set; }
}

/// <summary>
/// Handler to log audit events (immutable insert).
/// Idempotent: Multiple calls with same Id result in same outcome.
/// </summary>
public class LogAuditEventCommandHandler
{
    private readonly IDbConnection _db;
    private readonly AuditSql _sql;
    private readonly IClock _clock;
    private readonly ILogger<LogAuditEventCommandHandler> _logger;

    public LogAuditEventCommandHandler(
        IDbConnection db,
        AuditSql sql,
        IClock clock,
        ILogger<LogAuditEventCommandHandler> logger)
    {
        _db = db;
        _sql = sql;
        _clock = clock;
        _logger = logger;
    }

    public async Task Handle(LogAuditEventCommand request, CancellationToken ct)
    {
        try
        {
            // Log immutable audit event
            await _sql.InsertAuditEventAsync(
                _db,
                request.Id,
                request.EventType,
                request.EntityType,
                request.EntityId,
                request.ActorEmail,
                request.ActorRole,
                request.EventAt,
                request.Result,
                request.ErrorMessage,
                request.Details,
                request.EvidenceLinks,
                request.IpAddress,
                request.UserAgent,
                request.CorrelationId,
                ct);

            // Track GDPR retention for 7 years (FSS requirement)
            var retentionEndsAt = _clock.UtcNow.UtcDateTime.AddYears(7);
            await _sql.InsertGdprRetentionAsync(
                _db,
                Guid.NewGuid(),
                request.Id,
                null,  // CustomerId would be extracted from request.Details if present
                new[] { GdprDataCategories.TradingHistory, GdprDataCategories.PortfolioData },
                retentionEndsAt,
                ct);

            _logger.LogInformation(
                "Audit event {EventId} logged: {EventType} for {EntityType} {EntityId}",
                request.Id, request.EventType, request.EntityType, request.EntityId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "Failed to log audit event {EventId}: {EventType} for {EntityType} {EntityId}",
                request.Id, request.EventType, request.EntityType, request.EntityId);
            throw;
        }
    }
}
