#ifndef STORE_H
#define STORE_H

#include "models.h"
#include <QList>
#include <QMap>

QT_BEGIN_NAMESPACE
class QJsonDocument;
class QNetworkReply;
QT_END_NAMESPACE

/// Represents an in-flight API operation.
/// Wraps a QNetworkReply: owns cleanup, parses JSON, and emits signals.
/// Automatically deletes itself after finished() fires.
class Operation : public QObject
{
  Q_OBJECT

public:
  explicit Operation(QNetworkReply *reply, QObject *parent = nullptr);

signals:
  void success(const QJsonDocument &response);
  void failed(const QString &message);
  void finished();
};

/// Central data store backed by the Orion API.
/// Holds cached state and exposes read-only accessors + mutating operations.
class Store : public QObject
{
  Q_OBJECT

public:
  explicit Store(QObject *parent = nullptr);

  // ── Read-only accessors ──

  const QList<Network> &networks() const;
  int networkCount() const;
  const Network *networkById(const QString &id) const;

  QList<Stream> streamsForNetwork(const QString &networkId) const;
  int streamCount(const QString &networkId) const;
  const Stream *streamById(const QString &id) const;

  const QList<Particle> &particlesForStream(const QString &streamId) const;
  int particleCount(const QString &streamId) const;
  const Particle *particleById(const QString &id) const;

  // ── Bootstrap ──

  Operation *loadStartupData();

  // ── Network operations ──

  Operation *createNetwork(const QString &name);
  Operation *fetchNetworks();
  Operation *fetchNetwork(const QString &networkId);
  Operation *addNetworkMembers(const QString &networkId, const QStringList &emails);
  Operation *removeNetworkMember(const QString &networkId, const QString &email);
  Operation *setStreamCapacity(const QString &networkId, int capacity);

  // ── Stream operations ──

  Operation *createStream(const QString &networkId, const QString &name,
                          const QString &description, const QString &visibility = "network_all",
                          const QStringList &members = {});
  Operation *fetchStream(const QString &streamId);
  Operation *updateStream(const QString &streamId, const QString &name, const QString &description);
  Operation *openStream(const QString &streamId);
  Operation *closeStream(const QString &streamId);
  Operation *addStreamMembers(const QString &streamId, const QStringList &emails);
  Operation *removeStreamMembers(const QString &streamId, const QStringList &emails);

  // ── Particle operations ──

  Operation *createParticle(const QString &streamId, const QString &type,
                            const QMap<QString, QVariant> &data);
  Operation *fetchParticle(const QString &particleId);
  Operation *updateParticle(const QString &particleId, const QMap<QString, QVariant> &data);
  Operation *deleteParticle(const QString &particleId);
  Operation *markParticleSeen(const QString &particleId);
  Operation *markParticlesSeen(const QStringList &particleIds);
  Operation *ackParticle(const QString &particleId);

  void setCurrentUserEmail(const QString &email);
  QString currentUserEmail() const;

signals:
  // ── Data-change signals ──

  void networksChanged();
  void streamsChanged(const QString &networkId);
  void particlesChanged(const QString &streamId);

  // Granular signals for in-place property updates (no structural change)
  void particleUpdated(const QString &streamId, const QString &particleId);
  void streamUpdated(const QString &streamId);

  void startupDataLoaded();
  void errorOccurred(const QString &message);

private:
  // ── Internal state ──

  QList<Network> m_networks;
  QMap<QString, QList<Particle>> m_particles; // streamId -> particles
  QMap<QString, int> m_networkIndex;          // networkId -> index in m_networks
  QMap<QString, QString> m_streamToNetwork;   // streamId -> networkId
  QString m_currentUserEmail;

  // ── JSON parsing ──

  static Human parseHuman(const QJsonObject &obj);
  static Network parseNetwork(const QJsonObject &obj);
  static Stream parseStream(const QJsonObject &obj);
  static Particle parseParticle(const QJsonObject &obj);
  void populateFromStartupData(const QJsonObject &root);

  // ── State mutation helpers ──

  void upsertNetwork(const Network &network);
  void upsertStream(const QString &networkId, const Stream &stream);
  void upsertParticle(const QString &streamId, const Particle &particle);
  void removeParticleFromState(const QString &particleId);

  /// Returns the streamId that contains the given particle, or empty QString.
  QString findStreamForParticle(const QString &particleId) const;

};

#endif // STORE_H
