using Prometheus;

namespace foodmarket.Api.Infrastructure.Observability;

/// <summary>Бизнес-метрики поверх стандартных HTTP/DB-счётчиков, которые
/// добавляет <c>prometheus-net.AspNetCore</c> через <c>UseHttpMetrics()</c>
/// и EF-интерсептор. Сюда выносим то, что важно знать на дашборде вне
/// зависимости от HTTP-кода: количество проведённых документов, ошибок
/// проведения, длительность запросов к БД (агрегат поверх интерсептора).
///
/// Multi-tenant: лейблы — только тип документа и outcome (success/error).
/// Tenant-метку НЕ добавляем — на крупном multi-tenant хосте это раздуло бы
/// cardinality. Если потребуется per-org разрез — отдельный endpoint
/// `/api/reports/...` уже есть, метрики остаются глобальным health-сигналом.</summary>
public static class AppMetrics
{
    /// <summary>Счётчик проведённых документов (Post). Метка <c>type</c>:
    /// "retail-sale", "supply", "enter", "loss", "transfer", "inventory",
    /// "supplier-return", "customer-return". Метрика инкрементится из
    /// <see cref="IncrementPosted"/> в коде контроллеров на успешном Post.</summary>
    public static readonly Counter DocumentsPosted = Metrics.CreateCounter(
        "food_market_documents_posted_total",
        "Количество успешно проведённых документов учёта.",
        new CounterConfiguration { LabelNames = new[] { "type" } });

    /// <summary>Счётчик ошибок при попытке проведения (BadRequest/Conflict
    /// и серверные сбои). Метка <c>type</c> — тот же, что у DocumentsPosted;
    /// <c>reason</c> — короткий код: "insufficient_stock", "serialization",
    /// "validation", "other".</summary>
    public static readonly Counter DocumentsError = Metrics.CreateCounter(
        "food_market_documents_error_total",
        "Количество ошибок при проведении документов.",
        new CounterConfiguration { LabelNames = new[] { "type", "reason" } });

    /// <summary>Алиас на DocumentsPosted с фиксированной меткой "retail-sale"
    /// — Sprint-spec явно перечисляет sales_posted_total в чек-листе.</summary>
    public static readonly Counter SalesPosted = Metrics.CreateCounter(
        "food_market_sales_posted_total",
        "Количество проведённых розничных чеков (alias-метрика).");

    /// <summary>Аналогично для приёмок.</summary>
    public static readonly Counter SuppliesPosted = Metrics.CreateCounter(
        "food_market_supplies_posted_total",
        "Количество проведённых приёмок (alias-метрика).");

    /// <summary>Гистограмма длительности EF Core SQL-запросов в секундах.
    /// Лейбл <c>kind</c> — "query" / "command" (SELECT vs CUD), помогает
    /// разделить read-heavy и write-heavy нагрузку. Buckets подобраны под
    /// типичные веб-операции 5мс…5с.</summary>
    public static readonly Histogram DbQueryDuration = Metrics.CreateHistogram(
        "food_market_db_query_duration_seconds",
        "Длительность EF Core SQL-запросов.",
        new HistogramConfiguration
        {
            LabelNames = new[] { "kind" },
            Buckets = new[] { 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10 },
        });

    /// <summary>Сахар: успешное проведение документа. Инкрементит общий
    /// counter + опциональный alias (для sales/supplies).</summary>
    public static void IncrementPosted(string type)
    {
        DocumentsPosted.WithLabels(type).Inc();
        switch (type)
        {
            case "retail-sale": SalesPosted.Inc(); break;
            case "supply":      SuppliesPosted.Inc(); break;
        }
    }

    public static void IncrementError(string type, string reason)
        => DocumentsError.WithLabels(type, reason).Inc();
}
