#pragma once

#include "PeerLink.hpp"
#include "WorldStepProcessor.hpp"
#include "Peer.pb.h"
#include "world/World.hpp"

#include <chrono>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

namespace tw::p2p {

// Encapsulates the peer-to-peer networking layer and lock-step simulation.
//
// Owns the PeerLink (transport), WorldStepProcessor (simulation), peer
// registry, action history, and ack tracking.  The caller (TestPeerNode)
// only needs to supply a World and forward a few lifecycle calls.
class PeerWorldController {
public:
    PeerWorldController(uint32_t self_id, uint16_t port,
                        std::unique_ptr<PeerLink> link,
                        const std::string& registry_path,
                        World* world);

    // Write this node's entry into the shared registry.
    void register_self();

    // Block until at least expected_count entries appear in the registry.
    bool wait_until_peers_registered(
        uint32_t expected_count,
        std::chrono::milliseconds timeout = std::chrono::milliseconds(30000));

    // Initiate outgoing connections to all higher-ID peers in the registry.
    void discover_and_connect();

    // Accept expected_count incoming connections via the PeerLink listener.
    void wait_for_connections(
        uint32_t expected_count,
        std::chrono::milliseconds timeout = std::chrono::milliseconds(2000));

    // One simulation tick.  Returns true if the world stepped forward.
    bool tick();

    uint32_t  self_id()        const { return m_self_id; }
    uint32_t  current_frame()  const { return m_processor.current_frame(); }
    uint64_t  rollbacks()      const { return m_processor.rollbacks(); }
    uint64_t  stepped_frames() const { return m_processor.stepped_frames(); }

    glm::vec3 peer_position(uint32_t peer_id) const {
        return m_processor.peer_position(peer_id);
    }

    const std::vector<uint32_t>& peer_ids() const { return m_peer_ids; }

private:
    uint32_t    m_self_id;
    uint16_t    m_port;
    std::string m_registry_path;

    std::unique_ptr<PeerLink> m_link;
    WorldStepProcessor        m_processor;

    std::vector<uint32_t>                     m_peer_ids;
    std::map<uint32_t, mmo::peer::PeerAction> m_self_history;
    std::unordered_map<uint32_t, uint32_t>    m_peer_acks;

    mmo::peer::PeerAction build_local_action(uint32_t frame) const;
    void send_history_to(uint32_t peer_id);
};

} // namespace tw::p2p
