#include "metric.hpp"

#include "metrics/collection_data.hpp"
#include "types/report_types.hpp"
#include "types/sensor_types.hpp"
#include "utils/labeled_tuple.hpp"
#include "utils/transform.hpp"

#include <sdbusplus/exception.hpp>

#include <algorithm>

Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn,
               CollectionTimeScope timeScopeIn,
               CollectionDuration collectionDurationIn,
               std::unique_ptr<interfaces::Clock> clockIn) :
    sensors(std::move(sensorsIn)),
    operationType(operationTypeIn), collectionTimeScope(timeScopeIn),
    collectionDuration(collectionDurationIn),
    collectionAlgorithms(
        metrics::makeCollectionData(sensors.size(), operationType,
                                    collectionTimeScope, collectionDuration)),
    clock(std::move(clockIn))
{}

void Metric::registerForUpdates(interfaces::MetricListener& listener)
{
    listeners.emplace_back(listener);
}

void Metric::unregisterFromUpdates(interfaces::MetricListener& listener)
{
    listeners.erase(
        std::remove_if(listeners.begin(), listeners.end(),
                       [&listener](const interfaces::MetricListener& item) {
        return &item == &listener;
    }),
        listeners.end());
}

void Metric::initialize()
{
    for (const auto& sensor : sensors)
    {
        sensor->registerForUpdates(weak_from_this());
    }
}

void Metric::deinitialize()
{
    for (const auto& sensor : sensors)
    {
        sensor->unregisterFromUpdates(weak_from_this());
    }
}

const std::vector<MetricValue>& Metric::getUpdatedReadings()
{
    const auto steadyTimestamp = clock->steadyTimestamp();
    const auto systemTimestamp =
        std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
            .count();

    for (size_t i = 0; i < collectionAlgorithms.size(); ++i)
    {
        if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp))
        {
            if (i < readings.size())
            {
                readings[i].timestamp = systemTimestamp;
                readings[i].value = *value;
            }
            else
            {
                if (i > readings.size())
                {
                    const auto idx = readings.size();
                    std::swap(collectionAlgorithms[i],
                              collectionAlgorithms[idx]);
                    std::swap(sensors[i], sensors[idx]);
                    i = idx;
                }

                readings.emplace_back(sensors[i]->metadata(), *value,
                                      systemTimestamp);
            }
        }
    }

    return readings;
}

void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp,
                           double value)
{
    auto& data = findAssociatedData(notifier);
    double newValue = data.update(timestamp, value);

    if (data.updateLastValue(newValue))
    {
        for (interfaces::MetricListener& listener : listeners)
        {
            listener.metricUpdated();
        }
    }
}

metrics::CollectionData&
    Metric::findAssociatedData(const interfaces::Sensor& notifier)
{
    auto it = std::find_if(
        sensors.begin(), sensors.end(),
        [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
    auto index = std::distance(sensors.begin(), it);
    return *collectionAlgorithms.at(index);
}

LabeledMetricParameters Metric::dumpConfiguration() const
{
    auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
        return LabeledSensorInfo(sensor->id().service, sensor->id().path,
                                 sensor->metadata());
    });

    return LabeledMetricParameters(std::move(sensorPath), operationType,
                                   collectionTimeScope, collectionDuration);
}

uint64_t Metric::metricCount() const
{
    return sensors.size();
}

void Metric::updateReadings(Milliseconds timestamp)
{
    for (auto& data : collectionAlgorithms)
    {
        if (std::optional<double> newValue = data->update(timestamp))
        {
            if (data->updateLastValue(*newValue))
            {
                for (interfaces::MetricListener& listener : listeners)
                {
                    listener.metricUpdated();
                }
                return;
            }
        }
    }
}

bool Metric::isTimerRequired() const
{
    if (collectionTimeScope == CollectionTimeScope::point)
    {
        return false;
    }

    if (collectionTimeScope == CollectionTimeScope::startup &&
        (operationType == OperationType::min ||
         operationType == OperationType::max))
    {
        return false;
    }

    return true;
}
