namespace KArtSell.Modules.ModelOperations.SellDecision;

using Dapper;
using System.Data;

public interface ISellDecisionSql
{
    Task InsertDecisionAsync(SellDecisionEntity decision, IDbConnection conn);
    Task InsertEvidenceAsync(SellDecisionEvidenceEntity evidence, IDbConnection conn);
    Task<SellDecisionEntity?> GetDecisionByIdAsync(Guid id, Guid correlationId, IDbConnection conn);
    Task<List<SellDecisionEntity>> GetDecisionsByStatusAsync(string status, int limit, int offset, IDbConnection conn);
    Task<List<SellDecisionEntity>> GetDecisionsByModelIdAsync(Guid modelId, int limit, int offset, IDbConnection conn);
    Task UpdateDecisionStatusAsync(Guid id, string status, Guid correlationId, IDbConnection conn);
    Task<List<SellDecisionEvidenceEntity>> GetEvidenceByDecisionIdAsync(Guid decisionId, IDbConnection conn);
}

public class SellDecisionSql : ISellDecisionSql
{
    public async Task InsertDecisionAsync(SellDecisionEntity decision, IDbConnection conn)
    {
        const string sql = """
            INSERT INTO model_operations.sell_decisions (
                id, model_id, status, pbo_score, dsr_metric, oos_performance,
                sell_priority, target_quantity, target_price, approval_id, execution_id,
                created_at, created_by, created_justification, published_at, correlation_id, revision
            ) VALUES (
                @id, @modelId, @status, @pboScore, @dsrMetric, @oosPerformance::jsonb,
                @sellPriority, @targetQuantity, @targetPrice, @approvalId, @executionId,
                @createdAt, @createdBy, @createdJustification, @publishedAt, @correlationId, @revision
            )
        """;

        await conn.ExecuteAsync(sql, new
        {
            decision.Id,
            decision.ModelId,
            decision.Status,
            decision.PboScore,
            decision.DsrMetric,
            decision.OosPerformance,
            decision.SellPriority,
            decision.TargetQuantity,
            decision.TargetPrice,
            decision.ApprovalId,
            decision.ExecutionId,
            decision.CreatedAt,
            decision.CreatedBy,
            decision.CreatedJustification,
            decision.PublishedAt,
            decision.CorrelationId,
            decision.Revision
        });
    }

    public async Task InsertEvidenceAsync(SellDecisionEvidenceEntity evidence, IDbConnection conn)
    {
        const string sql = """
            INSERT INTO model_operations.sell_decision_evidence (
                id, decision_id, evidence_type, evidence_url, validated_at, validator_email, comments, published_at, correlation_id
            ) VALUES (
                @id, @decisionId, @evidenceType, @evidenceUrl, @validatedAt, @validatorEmail, @comments, @publishedAt, @correlationId
            )
        """;

        await conn.ExecuteAsync(sql, new
        {
            evidence.Id,
            evidence.DecisionId,
            evidence.EvidenceType,
            evidence.EvidenceUrl,
            evidence.ValidatedAt,
            evidence.ValidatorEmail,
            evidence.Comments,
            evidence.PublishedAt,
            evidence.CorrelationId
        });
    }

    public async Task<SellDecisionEntity?> GetDecisionByIdAsync(Guid id, Guid correlationId, IDbConnection conn)
    {
        const string sql = """
            SELECT id, model_id, status, pbo_score, dsr_metric, oos_performance,
                   sell_priority, target_quantity, target_price, approval_id, execution_id,
                   created_at, created_by, created_justification, published_at, correlation_id, revision
            FROM model_operations.sell_decisions
            WHERE id = @id
              AND correlation_id = @correlationId
              AND published_at <= NOW()
            ORDER BY published_at DESC, revision DESC
            LIMIT 1
        """;

        return await conn.QueryFirstOrDefaultAsync<SellDecisionEntity>(sql, new { id, correlationId });
    }

    public async Task<List<SellDecisionEntity>> GetDecisionsByStatusAsync(string status, int limit, int offset, IDbConnection conn)
    {
        const string sql = """
            SELECT id, model_id, status, pbo_score, dsr_metric, oos_performance,
                   sell_priority, target_quantity, target_price, approval_id, execution_id,
                   created_at, created_by, created_justification, published_at, correlation_id, revision
            FROM model_operations.sell_decisions
            WHERE status = @status
              AND published_at <= NOW()
            ORDER BY published_at DESC, revision DESC
            LIMIT @limit OFFSET @offset
        """;

        var results = await conn.QueryAsync<SellDecisionEntity>(sql, new { status, limit, offset });
        return results.ToList();
    }

    public async Task<List<SellDecisionEntity>> GetDecisionsByModelIdAsync(Guid modelId, int limit, int offset, IDbConnection conn)
    {
        const string sql = """
            SELECT id, model_id, status, pbo_score, dsr_metric, oos_performance,
                   sell_priority, target_quantity, target_price, approval_id, execution_id,
                   created_at, created_by, created_justification, published_at, correlation_id, revision
            FROM model_operations.sell_decisions
            WHERE model_id = @modelId
              AND published_at <= NOW()
            ORDER BY published_at DESC, revision DESC
            LIMIT @limit OFFSET @offset
        """;

        var results = await conn.QueryAsync<SellDecisionEntity>(sql, new { modelId, limit, offset });
        return results.ToList();
    }

    public async Task UpdateDecisionStatusAsync(Guid id, string status, Guid correlationId, IDbConnection conn)
    {
        const string sql = """
            UPDATE model_operations.sell_decisions
            SET status = @status,
                revision = revision + 1,
                published_at = NOW()
            WHERE id = @id
              AND correlation_id = @correlationId
        """;

        await conn.ExecuteAsync(sql, new { id, status, correlationId });
    }

    public async Task<List<SellDecisionEvidenceEntity>> GetEvidenceByDecisionIdAsync(Guid decisionId, IDbConnection conn)
    {
        const string sql = """
            SELECT id, decision_id, evidence_type, evidence_url, validated_at, validator_email, comments, published_at, correlation_id
            FROM model_operations.sell_decision_evidence
            WHERE decision_id = @decisionId
              AND published_at <= NOW()
            ORDER BY published_at DESC
        """;

        var results = await conn.QueryAsync<SellDecisionEvidenceEntity>(sql, new { decisionId });
        return results.ToList();
    }
}
