using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;

namespace foodmarket.Api.Infrastructure.Observability;

/// <summary>EF Core <c>DbCommandInterceptor</c>, который засекает время каждого
/// SQL-запроса и пишет в <see cref="AppMetrics.DbQueryDuration"/>. Использует
/// диагностический контекст <c>CommandEventData.StartTime</c> чтобы корректно
/// измерить именно execution-фазу (без подготовки и инициализации соединения).
///
/// Лейбл <c>kind</c>:
/// • "query"   — SELECT (Reader/Scalar);
/// • "command" — INSERT/UPDATE/DELETE/EXECUTE (NonQuery).
///
/// Интерсептор регистрируется в DI как Singleton — он stateless. EF DbContext
/// подхватывает его через <c>AddInterceptors</c>.</summary>
public sealed class DbMetricsInterceptor : DbCommandInterceptor
{
    public override ValueTask<DbDataReader> ReaderExecutedAsync(
        DbCommand command, CommandExecutedEventData eventData, DbDataReader result,
        CancellationToken cancellationToken = default)
    {
        AppMetrics.DbQueryDuration.WithLabels("query").Observe(eventData.Duration.TotalSeconds);
        return base.ReaderExecutedAsync(command, eventData, result, cancellationToken);
    }

    public override DbDataReader ReaderExecuted(
        DbCommand command, CommandExecutedEventData eventData, DbDataReader result)
    {
        AppMetrics.DbQueryDuration.WithLabels("query").Observe(eventData.Duration.TotalSeconds);
        return base.ReaderExecuted(command, eventData, result);
    }

    public override ValueTask<int> NonQueryExecutedAsync(
        DbCommand command, CommandExecutedEventData eventData, int result,
        CancellationToken cancellationToken = default)
    {
        AppMetrics.DbQueryDuration.WithLabels("command").Observe(eventData.Duration.TotalSeconds);
        return base.NonQueryExecutedAsync(command, eventData, result, cancellationToken);
    }

    public override int NonQueryExecuted(
        DbCommand command, CommandExecutedEventData eventData, int result)
    {
        AppMetrics.DbQueryDuration.WithLabels("command").Observe(eventData.Duration.TotalSeconds);
        return base.NonQueryExecuted(command, eventData, result);
    }

    public override ValueTask<object?> ScalarExecutedAsync(
        DbCommand command, CommandExecutedEventData eventData, object? result,
        CancellationToken cancellationToken = default)
    {
        AppMetrics.DbQueryDuration.WithLabels("query").Observe(eventData.Duration.TotalSeconds);
        return base.ScalarExecutedAsync(command, eventData, result, cancellationToken);
    }

    public override object? ScalarExecuted(
        DbCommand command, CommandExecutedEventData eventData, object? result)
    {
        AppMetrics.DbQueryDuration.WithLabels("query").Observe(eventData.Duration.TotalSeconds);
        return base.ScalarExecuted(command, eventData, result);
    }
}
