using FastEndpoints;
using Microsoft.Extensions.Logging;
using KArtSell.BuildingBlocks.Observability;

namespace KArtSell.Host.Features.Observability;

/// <summary>
/// GET /api/observability/metrics
/// Returns 5 key operational metrics for monitoring:
/// 1. Batch SLA (job completion times)
/// 2. Data Quality Quarantine (dq events)
/// 3. Duplicate Detection (outbox duplicates)
/// 4. Reconciliation Breaks (Evidence vs actual state mismatch)
/// 5. Model Drift (OOS performance degradation)
/// Uses PIT (point-in-time) queries with published_at <= cutoff.
/// </summary>
public class GetMetricsEndpoint : Endpoint<EmptyRequest, MetricsResponse>
{
    private readonly MetricsPolicy _policy;
    private readonly MetricsSql _sql;
    private readonly ILogger<GetMetricsEndpoint> _logger;

    private static readonly Action<ILogger, Exception?> LogMetricsRequested =
        LoggerMessage.Define(
            LogLevel.Information,
            new EventId(1, nameof(LogMetricsRequested)),
            "Observability metrics requested");

    public GetMetricsEndpoint(MetricsPolicy policy, MetricsSql sql, ILogger<GetMetricsEndpoint> logger)
    {
        _policy = policy;
        _sql = sql;
        _logger = logger;
    }

    public override void Configure()
    {
        Get("/observability/metrics");
        Roles("Admin", "Analyst", "Auditor");  // Financial compliance requires authentication
    }

    public override async Task HandleAsync(EmptyRequest req, CancellationToken ct)
    {
        LogMetricsRequested(_logger, null);

        // 1. Query all metrics
        var batchSla = await _sql.GetBatchSlaAsync(ct);
        var dataQuality = await _sql.GetDataQualityQuarantineAsync(ct);
        var duplicates = await _sql.GetDuplicateDetectionAsync(ct);
        var reconciliation = await _sql.GetReconciliationBreaksAsync(ct);
        var modelDrift = await _sql.GetModelDriftAsync(ct);

        // 2. Apply business rules (policy)
        var response = _policy.BuildMetricsResponse(
            batchSla,
            dataQuality,
            duplicates,
            reconciliation,
            modelDrift);

        // 3. Return 200 OK with response
        HttpContext.Response.StatusCode = 200;
        await HttpContext.Response.WriteAsJsonAsync(response, ct);
    }
}

public class EmptyRequest
{
    public string? _placeholder { get; set; }  // FastEndpoints requires ≥1 public property
}

public class MetricsResponse
{
    public BatchSlaMetrics BatchSla { get; set; } = new();
    public DataQualityMetrics DataQuality { get; set; } = new();
    public DuplicateDetectionMetrics Duplicates { get; set; } = new();
    public ReconciliationMetrics Reconciliation { get; set; } = new();
    public ModelDriftMetrics ModelDrift { get; set; } = new();
    public DateTime MeasuredAt { get; set; }
}

public class BatchSlaMetrics
{
    public int TotalJobs { get; set; }
    public int OnTimeJobs { get; set; }
    public decimal SlaPercentage { get; set; }
    public TimeSpan AverageCompleteionTime { get; set; }
}

public class DataQualityMetrics
{
    public int QuarantinedJobs { get; set; }
    public int TotalJobs { get; set; }
    public decimal QualityPercentage { get; set; }
    public List<string> RecentErrors { get; set; } = new();
}

public class DuplicateDetectionMetrics
{
    public int DuplicatesDetected { get; set; }
    public int DuplicatesResolved { get; set; }
    public DateTime LastCheckAt { get; set; }
}

public class ReconciliationMetrics
{
    public int BreaksDetected { get; set; }
    public int BreaksResolved { get; set; }
    public List<string> PendingBreaks { get; set; } = new();
}

public class ModelDriftMetrics
{
    public decimal BaselineSharpe { get; set; }
    public decimal CurrentSharpe { get; set; }
    public decimal DriftPercentage { get; set; }
    public string Status { get; set; } = "OK";  // OK, WARNING, CRITICAL
}
