#pragma once

#include <libwebsockets.h>
#include "connection_guard.h"
#include "connection_pool.h"
#include "message_broker.h"
#include <nlohmann/json.hpp>
#include <string>
#include <atomic>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <queue>
#include <condition_variable>
#include <unordered_map>
#include <vector>
#include <memory>
#include <chrono>

struct WebSocketUserData {
    std::string userId;
    bool pongReceived = true;
    std::queue<std::string> messageQueue;
    std::mutex messageQueueMutex;
    std::chrono::steady_clock::time_point connectionTime;  // Zeitpunkt der Verbindungsherstellung
    std::chrono::steady_clock::time_point lastPingTime;
    std::chrono::steady_clock::time_point lastPongTime;
    int pingTimeoutCount = 0;
    static constexpr int MAX_PING_TIMEOUTS = 5;  // Mehr Versuche bevor Trennung
    static constexpr int PING_INTERVAL_SECONDS = 30;
    static constexpr int PONG_TIMEOUT_SECONDS = 60;  // Längeres Timeout (Browser können länger brauchen)
};

class Worker; // forward

class WebSocketServer {
public:
    WebSocketServer(int port, ConnectionPool &pool, MessageBroker &broker, 
                   bool useSSL = false, const std::string& certPath = "", const std::string& keyPath = "");
    ~WebSocketServer();

    void run();
    void stop();
    void setWorkers(const std::vector<std::unique_ptr<Worker>> &workerList);

private:
    void startServer();
    void processMessageQueue();
    void pingClients();
    void handleBrokerMessage(const std::string &message);
    std::string getUserIdFromFalukantUserId(int falukantUserId);
    bool isMainAdmin(const std::string &hashedUserId);
    nlohmann::json getActiveConnections();
    void sendMessageToConnection(struct lws *wsi, const std::string &message);
    void sendMessageToConnection(struct lws *wsi, WebSocketUserData *ud, const std::string &message);
    void addConnection(const std::string &userId, struct lws *wsi);
    void removeConnection(const std::string &userId, struct lws *wsi);
    void removeConnectionByWsi(struct lws *wsi);  // Entfernt Verbindung aus allen Einträgen (Fallback)

    static int wsCallback(struct lws *wsi,
                          enum lws_callback_reasons reason,
                          void *user, void *in, size_t len);

    int port;
    ConnectionPool &pool;
    MessageBroker &broker;
    bool useSSL;
    std::string certPath;
    std::string keyPath;

    std::atomic<bool> running{false};
    struct lws_context *context = nullptr;
    std::thread serverThread;
    std::thread messageThread;
    std::thread pingThread;

    std::mutex queueMutex;
    std::condition_variable queueCV;
    std::queue<std::string> messageQueue;

    std::shared_mutex connectionsMutex;
    std::unordered_map<std::string, std::vector<struct lws*>> connections;
    std::vector<struct lws*> allConnections;  // Alle aktiven Verbindungen (auch ohne userId)

    std::vector<Worker*> workers;

    static struct lws_protocols protocols[];
    static WebSocketServer* instance;
};
