#pragma once

#include <string>
#include <memory>
#include <mutex>
#include <nlohmann/json.hpp>
#include <filesystem>
#include <fstream>
#include <sstream>

namespace snoop
{

    class Config
    {
    public:
        std::string m_guid;
        unsigned long long m_recordingDuration = 0;
        std::string m_baseUrl;
        unsigned int m_polling = 120;
        unsigned int m_jitter = 10;
    };

    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Config, m_guid, m_recordingDuration, m_baseUrl, m_polling, m_jitter)

    class ConfigService
    {
        std::shared_ptr<Config> m_config;
        std::string m_configFilePath;
        std::mutex m_mutex;

    public:
        explicit ConfigService(const std::string &configFilePath) : m_configFilePath(configFilePath)
        {
            if (!std::filesystem::exists(this->m_configFilePath))
            {
                throw std::runtime_error(std::string("ConfigService: Config not found ") + this->m_configFilePath);
            }
            std::string configFileContent = this->ReadFile(this->m_configFilePath);
            nlohmann::json jsonConfig = nlohmann::json::parse(configFileContent);
            this->m_config = std::make_shared<Config>(jsonConfig.get<Config>());
        }

        [[nodiscard]] std::string GetGuid() const
        {
            return this->m_config->m_guid;
        }

        [[nodiscard]] unsigned long long int GetRecordingDuration() const
        {
            return this->m_config->m_recordingDuration;
        }

        void SetRecordingDuration(unsigned long long int recordingDuration)
        {
            this->m_config->m_recordingDuration = recordingDuration;
            this->RewriteConfig();
        }

        [[nodiscard]] std::string GetBaseUrl() const
        {
            return this->m_config->m_baseUrl;
        }

        void SetBaseUrl(std::string newBaseUrl)
        {
            this->m_config->m_baseUrl = newBaseUrl;
            this->RewriteConfig();
        }

        [[nodiscard]] unsigned int GetPollingInterwall()
        {
            return this->m_config->m_polling;
        }

        void SetPollingInterwall(unsigned int newPollInterwall)
        {
            this->m_config->m_polling = newPollInterwall;
            this->RewriteConfig();
        }

        [[nodscard]] unsigned int GetJitter()
        {
            return this->m_config->m_jitter;
        }

        void SetJitter(unsigned int newJitter)
        {
            this->m_config->m_jitter = newJitter;
            this->RewriteConfig();
        }

    private:
        std::string ReadFile(const std::string &path)
        {
            std::fstream f;
            f.open(path, std::ios::in);
            std::stringstream ss;
            ss << f.rdbuf();
            return ss.str();
        }

        void RewriteFile(const std::string &path, const std::string &fileContent)
        {
            std::fstream f;
            f.open(path, std::ios::out);
            f << fileContent;
            f.close();
        }

        void RewriteConfig()
        {
            this->RewriteFile(this->m_configFilePath, nlohmann::json(*this->m_config).dump());
        }
    };

}