#pragma once
#include "modbus_exception.hpp"
#include "itransport.hpp"
#include "transport_error.hpp"

#include <cstdint>
#include <vector>
#include <chrono>
#include <string>

class ModbusTCP : public ITransport {
public:
    ModbusTCP();
    ~ModbusTCP() override;

    bool connect(const char* host, std::uint16_t port) override;
    void disconnect() override;
    bool is_connected() const override;
  
    TransportState state() const override { return state_; }
    TransportError last_error() const override { return last_error_; }

    bool read_registers(std::uint16_t addr,
                        std::uint16_t count,
                        std::vector<std::uint16_t>& out) override;    

    bool write_registers(std::uint16_t addr,
                         const std::vector<std::uint16_t>& values) override;

    void poll() override; // watchdog

    void reset() override;

private:
    bool reconnect();
    bool recv_all(void* buf, std::size_t len);

private:
    // socket
    int sock_;
    std::uint16_t transaction_id_{0};

    // connection info
    std::string host_;
    std::uint16_t port_{0};

    // state machine
    TransportState state_{TransportState::Disconnected};
    TransportError last_error_{TransportError::None};
    ModbusException exception_;

    // watchdog
    static constexpr int WATCHDOG_SEC  = 5;
    static constexpr int MAX_RETRY     = 5;
    static constexpr int FAULT_RESET_SEC = 30; // Fault 후 자동 리셋 대기
    std::chrono::steady_clock::time_point last_ok_;
    std::chrono::steady_clock::time_point fault_since_;
    int retry_count_{0};
    bool can_io() const;

};
