#ifndef HC900_GATEWAY_H
#define HC900_GATEWAY_H

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <atomic>
#include <thread>
#include <mutex>
#include <chrono>

#include "modbus_gateway.grpc.pb.h"
#include "modbus_gateway.pb.h"

class Controller;

struct RegisterEntry {
    std::string tag;
    uint32_t addr;
    uint32_t write_addr; // address used for writes; defaults to addr. Differs for loop MODE
                         // (read=Loop Status / LOOPSTAT, write=Auto/Manual State / MODEIN)
    uint32_t count;   // register count (1 or 2)
    std::string type; // "float32" or "uint16"
    std::string access; // "R" or "RW"
};

struct CachedValue {
    float float32_val;
    uint32_t uint16_val;
    bool is_float;
    uint32_t quality; // 192=good, 0=bad
    std::chrono::system_clock::time_point timestamp;
};

// One gateway process serves exactly one HC900 controller. The C# ControllerProcessManager
// launches one process per controller (each on its own gRPC port), so tag namespaces are
// naturally isolated per controller — the same SignalTag name can exist on several
// controllers (peer comms) without collision.
class Hc900Gateway final {
public:
    Hc900Gateway(const std::string& host, uint16_t port,
                 const std::string& map_path,
                 int poll_interval_ms = 1000,
                 int grpc_port = 50051);
    ~Hc900Gateway();

    bool Start();
    void Stop();

private:
    void PollLoop();
    void LoadRegisterMap(const std::string& path);
    void ReadAllRegisters();

    // gRPC service implementation
    class GatewayServiceImpl final : public hc900::ModbusGateway::Service {
    public:
        GatewayServiceImpl(Hc900Gateway& gateway);
        grpc::Status ReadTags(grpc::ServerContext* ctx,
                              const hc900::ReadTagsRequest* req,
                              hc900::ReadTagsResponse* resp) override;
        grpc::Status WriteTag(grpc::ServerContext* ctx,
                              const hc900::WriteTagRequest* req,
                              hc900::WriteTagResponse* resp) override;
        grpc::Status ListTags(grpc::ServerContext* ctx,
                              const hc900::ListTagsRequest* req,
                              hc900::ListTagsResponse* resp) override;
        grpc::Status HealthCheck(grpc::ServerContext* ctx,
                                  const hc900::HealthCheckRequest* req,
                                  hc900::HealthCheckResponse* resp) override;
        grpc::Status StreamTags(grpc::ServerContext* ctx,
                                const hc900::StreamTagsRequest* req,
                                grpc::ServerWriter<hc900::TagValue>* writer) override;
    private:
        Hc900Gateway& gateway_;
    };

    std::string host_;
    uint16_t port_;
    int poll_interval_ms_;
    std::unique_ptr<Controller> controller_;

    // Register map
    std::vector<RegisterEntry> registers_;
    std::unordered_map<std::string, size_t> tag_index_;
    std::vector<size_t> sorted_indices_;  // indices into registers_, sorted by address

    // Cache
    std::unordered_map<std::string, CachedValue> cache_;
    mutable std::mutex cache_mutex_;

    // Transport — shared between poll thread and gRPC handlers
    mutable std::mutex transport_mutex_;

    // Poller
    std::atomic<bool> running_;
    std::thread poll_thread_;
    uint64_t poll_count_{0};
    std::chrono::milliseconds last_poll_duration_{0};

    // gRPC server
    std::unique_ptr<grpc::Server> grpc_server_;
    std::unique_ptr<GatewayServiceImpl> grpc_service_;
    std::string grpc_listen_;
};

#endif // HC900_GATEWAY_H
