using KArtSell.BuildingBlocks.Time;

namespace KArtSell.Host.Features.Observability;

/// <summary>
/// Business logic for metrics calculations and thresholds.
/// Pure functions: no I/O, only decision logic.
/// </summary>
public class MetricsPolicy(IClock clock)
{
    public MetricsResponse BuildMetricsResponse(
        (int Total, int OnTime, TimeSpan AvgTime)? batchSla,
        (int Quarantined, int Total, List<string> Errors)? dataQuality,
        (int Detected, int Resolved, DateTime LastCheck)? duplicates,
        (int Detected, int Resolved, List<string> Pending)? reconciliation,
        (decimal Baseline, decimal Current)? modelDrift)
    {
        return new MetricsResponse
        {
            BatchSla = BuildBatchSlaMetrics(batchSla),
            DataQuality = BuildDataQualityMetrics(dataQuality),
            Duplicates = BuildDuplicateMetrics(duplicates),
            Reconciliation = BuildReconciliationMetrics(reconciliation),
            ModelDrift = BuildModelDriftMetrics(modelDrift),
            MeasuredAt = clock.UtcNow.UtcDateTime
        };
    }

    private BatchSlaMetrics BuildBatchSlaMetrics((int Total, int OnTime, TimeSpan AvgTime)? data)
    {
        if (data == null)
            return new BatchSlaMetrics { SlaPercentage = 0 };

        var (total, onTime, avgTime) = data.Value;
        var percentage = total == 0 ? 0 : (decimal)onTime / total * 100;

        return new BatchSlaMetrics
        {
            TotalJobs = total,
            OnTimeJobs = onTime,
            SlaPercentage = Math.Round(percentage, 2),
            AverageCompleteionTime = avgTime
        };
    }

    private DataQualityMetrics BuildDataQualityMetrics((int Quarantined, int Total, List<string> Errors)? data)
    {
        if (data == null)
            return new DataQualityMetrics { QualityPercentage = 100 };

        var (quarantined, total, errors) = data.Value;
        var percentage = total == 0 ? 100 : (decimal)(total - quarantined) / total * 100;

        return new DataQualityMetrics
        {
            QuarantinedJobs = quarantined,
            TotalJobs = total,
            QualityPercentage = Math.Round(percentage, 2),
            RecentErrors = errors
        };
    }

    private DuplicateDetectionMetrics BuildDuplicateMetrics((int Detected, int Resolved, DateTime LastCheck)? data)
    {
        if (data == null)
            return new DuplicateDetectionMetrics();

        var (detected, resolved, lastCheck) = data.Value;

        return new DuplicateDetectionMetrics
        {
            DuplicatesDetected = detected,
            DuplicatesResolved = resolved,
            LastCheckAt = lastCheck
        };
    }

    private ReconciliationMetrics BuildReconciliationMetrics((int Detected, int Resolved, List<string> Pending)? data)
    {
        if (data == null)
            return new ReconciliationMetrics();

        var (detected, resolved, pending) = data.Value;

        return new ReconciliationMetrics
        {
            BreaksDetected = detected,
            BreaksResolved = resolved,
            PendingBreaks = pending
        };
    }

    private ModelDriftMetrics BuildModelDriftMetrics((decimal Baseline, decimal Current)? data)
    {
        if (data == null)
            return new ModelDriftMetrics { Status = "NO_DATA" };

        var (baseline, current) = data.Value;
        var drift = baseline == 0 ? 0 : Math.Abs((current - baseline) / baseline * 100);
        var status = drift switch
        {
            >= 30 => "CRITICAL",
            >= 15 => "WARNING",
            _ => "OK"
        };

        return new ModelDriftMetrics
        {
            BaselineSharpe = Math.Round(baseline, 4),
            CurrentSharpe = Math.Round(current, 4),
            DriftPercentage = Math.Round(drift, 2),
            Status = status
        };
    }
}
