/**
 * @file Hub.h
 * @brief Central controller: owns the WS client, the source model, trigger
 *        state, capture, zoom caches and history info. Translates StreamHub WS
 *        messages into model updates and emits Qt signals for the UI.
 */

#pragma once

#include "Model.h"
#include "WsClient.h"
#include "Protocol.h"

#include <QObject>
#include <QString>
#include <vector>
#include <string>
#include <cstdint>

namespace shq {

/** Hi-res zoom cache (per plot; mirrors the ImGui client's PlotZoomCache). */
struct PlotZoomCache {
    bool     valid   = false;
    bool     pending = false;
    uint32_t reqId   = 0;
    double   t0 = 0.0, t1 = 0.0;        /* range of valid data */
    double   reqT0 = 0.0, reqT1 = 0.0;  /* range of pending request */
    std::vector<StreamHubClient::ZoomSignal> pts;
};

class Hub : public QObject {
    Q_OBJECT
public:
    explicit Hub(QObject* parent = nullptr);

    void start(const QString& host, uint16_t port);
    void reconnect(const QString& host, uint16_t port);

    /* ---- Model access (GUI thread only) -------------------------------- */
    std::vector<Source>&       sources()       { return sources_; }
    const std::vector<Source>& sources() const { return sources_; }
    TriggerCfgState&           trigger()       { return trigger_; }
    const StreamHubClient::HistoryInfoMsg& historyInfo() const { return historyInfo_; }
    uint32_t                   maxPoints() const { return maxPoints_; }
    bool                       isConnected() const { return ws_.isConnected(); }
    WsClient&                  ws() { return ws_; }

    const StreamHubClient::CaptureFrame* capture() const {
        return hasCapture_ ? &capture_ : nullptr;
    }
    void clearCapture() { hasCapture_ = false; }

    PlotZoomCache& zoomCache(int i)     { return zoomCache_[i]; }
    PlotZoomCache& histZoomCache(int i) { return histZoomCache_[i]; }

    int findSource(const std::string& id) const;
    int findSignal(const Source& src, const std::string& name) const;
    std::string slotKey(const PlotAssignment& a) const;

    /* ---- Commands ------------------------------------------------------ */
    void sendGetSources();
    void sendGetStats();
    void sendGetConfig(const std::string& sourceId);
    void sendAddSource(const std::string& label, const std::string& addr,
                       const std::string& mcast, uint16_t dataPort);
    void sendRemoveSource(const std::string& id);
    void sendSaveSources();
    void sendSetMaxPoints(uint32_t n);

    void sendSetTrigger(const std::string& key, const std::string& edge,
                        double threshold, double windowSec, double prePercent,
                        const std::string& mode);
    void sendArm();
    void sendDisarm();
    void sendRearm();
    void sendTrigStop(bool stopped);

    void requestZoom(int plotIdx, double t0, double t1, const std::string& csv);
    void requestHistoryZoom(int plotIdx, double t0, double t1, const std::string& csv);
    void sendHistoryInfo();

Q_SIGNALS:
    void connectedChanged(bool connected);
    void sourcesChanged();
    void configChanged(const QString& sourceId);
    void statsChanged();
    void triggerStateChanged();
    void captureReceived();
    void zoomReceived(int plotIdx);
    void historyZoomReceived(int plotIdx);
    void historyInfoChanged();
    void maxPointsChanged(uint32_t n);

private Q_SLOTS:
    void onConnected(bool connected);
    void onText(const QString& json);
    void onBinary(const QByteArray& data);

private:
    void onSources(const std::string& json);
    void onConfig(const std::string& json);
    void onStats(const std::string& json);
    void onTriggerState(const std::string& json);
    void onZoom(const std::string& json);
    void onHistoryZoom(const std::string& json);
    void onHistoryInfo(const std::string& json);
    void onMaxPointsUpdated(const std::string& json);

    WsClient            ws_;
    std::vector<Source> sources_;
    TriggerCfgState     trigger_;
    uint32_t            maxPoints_ = 1000000u;

    StreamHubClient::CaptureFrame   capture_;
    bool                            hasCapture_ = false;
    StreamHubClient::HistoryInfoMsg historyInfo_;

    PlotZoomCache zoomCache_[kMaxPlotSlots];
    PlotZoomCache histZoomCache_[kMaxPlotSlots];
    uint32_t      nextZoomReqId_ = 1;
    double        lastHistInfoReqMs_ = 0.0;
};

} /* namespace shq */
