namespace KArtSell.Modules.ModelOperations.SellDecision;

using System.Data;
using KArtSell.BuildingBlocks.Time;
using Npgsql;

public interface IGenerateSellDecisionHandler
{
    Task<CreateSellDecisionResponse> HandleAsync(CreateSellDecisionRequest request, Guid correlationId, string userId, CancellationToken ct);
}

public class GenerateSellDecisionHandler : IGenerateSellDecisionHandler
{
    private readonly string _connectionString;
    private readonly ISellDecisionSql _sql;
    private readonly IPboValidator _pboValidator;
    private readonly IDsrValidator _dsrValidator;
    private readonly IOosValidator _oosValidator;
    private readonly ISellPriorityRanker _ranker;
    private readonly IClock _clock;

    public GenerateSellDecisionHandler(
        string connectionString,
        ISellDecisionSql sql,
        IPboValidator pboValidator,
        IDsrValidator dsrValidator,
        IOosValidator oosValidator,
        ISellPriorityRanker ranker,
        IClock clock)
    {
        _connectionString = connectionString;
        _sql = sql;
        _pboValidator = pboValidator;
        _dsrValidator = dsrValidator;
        _oosValidator = oosValidator;
        _ranker = ranker;
        _clock = clock;
    }

    public async Task<CreateSellDecisionResponse> HandleAsync(CreateSellDecisionRequest request, Guid correlationId, string userId, CancellationToken ct)
    {
        // Validate thresholds are in reasonable range
        if (request.ThresholdPbo is < 0 or > 1)
            throw new ArgumentException("ThresholdPbo must be between 0 and 1");

        if (request.ThresholdDsr is < 0 or > 1)
            throw new ArgumentException("ThresholdDsr must be between 0 and 1");

        var decisionId = Guid.NewGuid();
        var now = _clock.UtcNow.UtcDateTime;

        using var conn = new NpgsqlConnection(_connectionString);
        await conn.OpenAsync(ct);

        // Retrieve Phase 1 evidence for model
        var oosData = await FetchOosDataAsync(request.ModelId, request.WindowStart, request.WindowEnd, conn, ct);

        // Validate gates
        var pboResult = _pboValidator.ValidatePboScore(oosData.PboScore, request.ThresholdPbo);
        var dsrResult = _dsrValidator.ValidateDsrMetric(oosData.DsrMetric, request.ThresholdDsr);
        var oosResult = _oosValidator.ValidateOosPerformance(oosData.OosPerformance, 0.0m);

        // Determine state based on validation results
        var state = DetermineState(pboResult.IsValid, dsrResult.IsValid, oosResult.IsValid);

        // Create decision record
        var decision = new SellDecisionEntity
        {
            Id = decisionId,
            ModelId = request.ModelId,
            Status = state,
            PboScore = oosData.PboScore,
            DsrMetric = oosData.DsrMetric,
            OosPerformance = oosData.OosPerformance,
            SellPriority = null,
            TargetQuantity = null,
            TargetPrice = null,
            CreatedAt = now,
            CreatedBy = userId,
            CreatedJustification = request.Justification,
            PublishedAt = now,
            CorrelationId = correlationId,
            Revision = 1
        };

        await _sql.InsertDecisionAsync(decision, conn);

        // Log evidence
        if (!string.IsNullOrEmpty(oosData.PboReportUrl))
        {
            var pboEvidence = new SellDecisionEvidenceEntity
            {
                Id = Guid.NewGuid(),
                DecisionId = decisionId,
                EvidenceType = "PBO_REPORT",
                EvidenceUrl = oosData.PboReportUrl,
                ValidatedAt = now,
                ValidatorEmail = userId,
                Comments = pboResult.Reason,
                PublishedAt = now,
                CorrelationId = correlationId
            };
            await _sql.InsertEvidenceAsync(pboEvidence, conn);
        }

        if (!string.IsNullOrEmpty(oosData.DsrReportUrl))
        {
            var dsrEvidence = new SellDecisionEvidenceEntity
            {
                Id = Guid.NewGuid(),
                DecisionId = decisionId,
                EvidenceType = "DSR_METRIC",
                EvidenceUrl = oosData.DsrReportUrl,
                ValidatedAt = now,
                ValidatorEmail = userId,
                Comments = dsrResult.Reason,
                PublishedAt = now,
                CorrelationId = correlationId
            };
            await _sql.InsertEvidenceAsync(dsrEvidence, conn);
        }

        return new CreateSellDecisionResponse
        {
            DecisionId = decisionId,
            ModelId = request.ModelId,
            Status = state,
            CorrelationId = correlationId,
            CreatedAt = now
        };
    }

    private string DetermineState(bool pboValid, bool dsrValid, bool oosValid)
    {
        if (!pboValid || !dsrValid || !oosValid)
            return SellDecisionStatus.ReadyForApproval.ToString();

        return SellDecisionStatus.OosApproved.ToString();
    }

    private async Task<OosDataDto> FetchOosDataAsync(Guid modelId, DateTime windowStart, DateTime windowEnd, IDbConnection conn, CancellationToken ct)
    {
        // Stub: In real implementation, this fetches from Phase 1 evidence store
        // For now, return mock data (Phase 1 would populate actual evidence)
        return new OosDataDto
        {
            PboScore = 0.72m,
            DsrMetric = 0.018m,
            OosPerformance = "0.08",
            PboReportUrl = $"s3://evidence/{modelId}/PBO_REPORT.json",
            DsrReportUrl = $"s3://evidence/{modelId}/DSR_METRIC.json"
        };
    }

    private sealed class OosDataDto
    {
        public decimal? PboScore { get; set; }
        public decimal? DsrMetric { get; set; }
        public required string OosPerformance { get; set; }
        public required string PboReportUrl { get; set; }
        public required string DsrReportUrl { get; set; }
    }
}
