#pragma once

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include <visa.h>

#include "radar_driver.hpp"
#include "run_config.hpp"

namespace radar::drivers {

struct CompactMK209DriverSettings {
    std::string resource{};
    config::RadarSweepSettings sweep{};
    std::uint32_t timeout_ms = 20'000;
    bool preset_on_open = true;
};

class CompactMK209Driver final : public RadarDriver {
  public:
    explicit CompactMK209Driver(CompactMK209DriverSettings settings);
    ~CompactMK209Driver() override;

    void open() override;
    void close() override;
    [[nodiscard]] auto acquire_sweep() -> SweepTrace override;

    [[nodiscard]] auto query_identity() -> std::string;
    [[nodiscard]] auto query_system_error() -> std::string;

  private:
    void configure_device();
    void expect_operation_complete(const std::string& command, const std::string& context);

    void write_command(const std::string& command);
    [[nodiscard]] auto query_string(const std::string& command) -> std::string;
    [[nodiscard]] auto query_float_array(const std::string& command, std::uint32_t expected_values)
        -> std::vector<float>;
    [[nodiscard]] auto query_sweep_trace_pair(std::uint32_t points)
        -> std::pair<std::vector<float>, std::vector<float>>;
    [[nodiscard]] auto read_float_array_response(const std::string& context, std::uint32_t expected_values)
        -> std::vector<float>;

    [[nodiscard]] auto read_ascii_token() -> std::string;
    [[nodiscard]] auto read_line() -> std::string;
    [[nodiscard]] auto read_byte() -> std::uint8_t;
    [[nodiscard]] auto read_exact(std::uint64_t size) -> std::vector<std::uint8_t>;
    [[nodiscard]] auto read_ieee_block() -> std::vector<std::uint8_t>;

    void check_status(ViStatus status, const std::string& context) const;
    [[nodiscard]] auto status_message(ViStatus status) const -> std::string;
    void require_open() const;

    [[nodiscard]] static auto float_array_from_little_endian(std::vector<std::uint8_t> bytes) -> std::vector<float>;
    [[nodiscard]] static auto complex_trace_from_interleaved(const std::vector<float>& values)
        -> std::vector<ipc::Complex32>;
    [[nodiscard]] static auto format_frequency(float value_hz) -> std::string;
    [[nodiscard]] static auto format_power(float value_dbm) -> std::string;
    [[nodiscard]] static auto trim_ascii(std::string value) -> std::string;

    CompactMK209DriverSettings settings_{};
    std::vector<float> frequency_hz_{};
    bool is_open_ = false;
    ViSession resource_manager_ = VI_NULL;
    ViSession instrument_ = VI_NULL;
};

}  // namespace radar::drivers
