#include <exception>
#include <nlohmann/json.hpp>
#include <solar/logger/envoydata.hpp>
#include <spdlog/spdlog.h>
#include <stdexcept>

nlohmann::basic_json<> ExtractEnvoyProductionInvertersObject(std::string const & json)
{
    auto const parsed = nlohmann::json::parse(json);
    if(!parsed.is_object())
    {
        throw std::runtime_error("Invalid JSON");
    }

    auto const production = parsed["production"];
    if(!production.is_array())
    {
        throw std::runtime_error("Invalid production property type");
    }

    auto const invertersObject = std::find_if(
        production.begin(),
        production.end(),
        [](nlohmann::basic_json<> const & item)
        { return item.is_object() && item["type"].is_string() && item["type"].get<std::string>() == "inverters"; });
    if(invertersObject == production.end())
    {
        throw std::runtime_error("Failed to find JSON object of type inverters in production array");
    }

    if(!(*invertersObject)["activeCount"].is_number_integer())
    {
        throw std::runtime_error("Invalid activeCount property in inverters object");
    }
    if(!(*invertersObject)["readingTime"].is_number_integer())
    {
        throw std::runtime_error("Invalid readingTime property in inverters object");
    }
    if(!(*invertersObject)["wNow"].is_number_integer())
    {
        throw std::runtime_error("Invalid wNow property in inverters object");
    }
    if(!(*invertersObject)["whLifetime"].is_number_integer())
    {
        throw std::runtime_error("Invalid whLifetime property in inverters object");
    }

    return *invertersObject;
}

std::optional<EnvoyData> EnvoyData::ParseJson(std::string const & json)
{
    try
    {
        auto const parsed = ExtractEnvoyProductionInvertersObject(json);
        return EnvoyData {
            .type = parsed["type"].get<std::string>(),
            .activeCount = parsed["activeCount"].get<std::int32_t>(),
            .readingTime = parsed["readingTime"].get<std::int64_t>(),
            .wNow = parsed["wNow"].get<std::int32_t>(),
            .whLifetime = parsed["whLifetime"].get<std::int64_t>(),
        };
    }
    catch(std::exception & ex)
    {
        spdlog::error("Unexpected exception {} whilst parsing JSON {}", ex.what(), json);
        return {};
    }
}
