#pragma once

#include <string>
#include <set>
#include <map>
#include <nlohmann/json.hpp>
#include <httplib.h>

namespace CppModelBase
{
    typedef std::set<std::string> SimulationNamesListType;
    typedef std::string AgentInfoType;
    typedef nlohmann::json InputDataType;
    typedef nlohmann::json ParameterDataType;
    typedef nlohmann::json ResultDataType;
    typedef nlohmann::json SimulationDataType;

    enum class Environment
    {
        Local,
        Staging,
        Production
    };

    class ApiConnector
    {
    private:
        std::string token = "";
        std::string refreshToken = "";
        std::string hostname = "";
        httplib::Server loginServer;
        Environment environment;

        std::string apiHost;
        unsigned int apiPort;
        std::string authHost;
        std::string authRealm;
        std::string clientId;
        std::string clientSecret;

        void GetLoginResult(const httplib::Request &req, httplib::Response &res);
        void AwaitServer();

        void Relogin();

        void OpenBrowser(const std::string &url);

        std::string StartLocalServer();

        std::string ExchangeAuthCodeForToken(const std::string &code);
        std::string RefreshAccessToken();

        void LoadTokenFromFile();
        void StoreTokens(const std::string &accessToken, const std::string &refreshToken);
        bool IsTokenExpired(const std::string &token);
        void ResolveHostname();

        std::string GetAuthServerUrl();

        static Environment ParseEnvironment(const std::string &env);

    public:
        ApiConnector();
        ApiConnector(Environment env);
        ~ApiConnector();
        std::string GetFirstGroup(std::string token);
        std::string GetHostname();
        unsigned int GetPort();
        std::string GetApiKey();
        std::string Login();

        // System
        nlohmann::json GetVersion();

        // Agent
        nlohmann::json GetAgent();
        nlohmann::json SendAgentCommand(const std::string &command);

        // Simulations
        nlohmann::json GetSimulations(const std::string &scope = "user", int limit = 50, int offset = 0);
        nlohmann::json GetSimulationData(const std::string &simulationId);
        void DeleteSimulation(const std::string &simulationId);

        // Simulation inputs
        nlohmann::json GetSimulationInputs(const std::string &simulationId);
        void PostSimulationInputs(const std::string &simulationId, const nlohmann::json &inputs);

        // Executions
        nlohmann::json GetExecutions(const std::string &simulationId, int limit = 50, int offset = 0);
        nlohmann::json PostExecution(const std::string &simulationId, const nlohmann::json &data);
        nlohmann::json GetExecution(const std::string &simulationId, const std::string &executionId);

        // Project generation
        nlohmann::json GenerateProject(const nlohmann::json &request);

        // Users
        nlohmann::json GetUsers(int limit = 50, int offset = 0);
        nlohmann::json CreateUser(const std::string &email, const std::string &role);
        nlohmann::json GetUser(const std::string &userId);
        nlohmann::json UpdateUser(const std::string &userId, const std::string &role);
        void DeleteUser(const std::string &userId);

        Environment GetEnvironment() const;

        // Deprecated — kept for backwards compatibility
        SimulationNamesListType GetSimulationNames();
        SimulationDataType GetSimulationPreexecutionData(const std::string &simulationName);
        void PutSimulationData(const std::string &simulationName, SimulationDataType &simulationData);
    };
}
