/*
 * SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
 * Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 * SPDX-License-Identifier: LicenseRef-NvidiaProprietary
 *
 * NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
 * property and proprietary rights in and to this material, related
 * documentation and any modifications thereto. Any use, reproduction,
 * disclosure or distribution of this material and related documentation
 * without an express license agreement from NVIDIA CORPORATION or
 * its affiliates is strictly prohibited.
 */

#pragma once

// std
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <limits>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
// 3rd party
#include "nlohmann/json.hpp"
// sharp_am
#include "histogram.h"

/**
 * Telemetry's metrics
 *
 * NOTE:
 *   fields names are by spec, so DON'T change public fields' name
 */
struct Metrics
{
    struct Metadata
    {
        explicit Metadata(std::string host) : host{std::move(host)} {}

        std::string host;
        std::time_t timestamp{};
    };

    struct History
    {
        std::time_t starting_timestamp{std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())};
        int64_t denied_reservations{};                   // not likely, due to duplicated guids
        int64_t denied_jobs_by_reservations{};           // guids dont match the reservation
        int64_t denied_jobs_by_resource_limit{};         // Reservation resource limit
        int64_t denied_jobs_by_no_resources{};           // No available route to serve the job
        int64_t jobs_ended_due_to_client_failure{};      // Keepalive detected no client'
        int64_t jobs_ended_due_to_fatal_sharp_error{};   // For example, link failure.
        int64_t jobs_ended_successfully{};
    };

    struct Helpers
    {
        std::set<uint64_t> ended_jobs_that_could_not_be_cleaned;
    };

    struct Config
    {
        HoursHistogram::Buckets ended_jobs_duration_in_hours_buckets;
        IntegralHistogram::Buckets active_jobs_num_hcas_buckets;
        IntegralHistogram::Buckets trees_level_buckets;
    };

    //! ctor. we need to know the histograms buckets, so we get it in config
    explicit Metrics(Config config, std::string host);

    //! reset metrics' counters.
    //! zero out all metrics counters, but keep the bucket configuration & metadata intact.
    void ResetCounters();

    Metadata metadata;
    int64_t active_jobs{};
    int64_t active_sat_jobs{};
    int64_t agg_nodes_in_invalid_state{};               // Reported in sharp status API
    IntegralHistogram active_jobs_num_hcas_histogram;   // default buckets: 8,16,32,64,128,256,512,1024,inifinity
    IntegralHistogram trees_level_histogram;            // default buckets: 0,1,2,3
    History history;
    HoursHistogram history_ended_jobs_duration_in_hours_histogram{};
    Helpers helpers;   // default buckets: 1,12,24,72,168
};

// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Metrics::Metadata, host, timestamp);
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Metrics::History,
//                                    denied_reservations,
//                                    denied_jobs_by_reservations,
//                                    denied_jobs_by_resource_limit,
//                                    denied_jobs_by_no_resources,
//                                    jobs_ended_due_to_client_failure,
//                                    jobs_ended_due_to_fatal_sharp_error,
//                                    jobs_ended_successfully);
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Metrics,
//                                    metadata,
//                                    active_jobs,
//                                    active_sat_jobs,
//                                    active_jobs_num_hcas_histogram,
//                                    agg_nodes_in_invalid_state,
//                                    active_jobs_num_hcas_histogram,
//                                    trees_level_histogram,
//                                    history,
//                                    history_ended_jobs_duration_in_hours_histogram);
// NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Metrics::Config, ended_jobs_duration_in_hours_buckets, active_jobs_num_hcas_buckets,
// trees_level_buckets);

// jsonize Metrics
void to_json(nlohmann::ordered_json& j, const Metrics& h);
void from_json(const nlohmann::ordered_json& j, Metrics& h);
void to_json(nlohmann::ordered_json& j, const Metrics::Config& config);
void from_json(const nlohmann::ordered_json& j, Metrics::Config& config);
