#pragma once

#include <chrono>
#include <cstdint>
#include <deque>
#include <optional>
#include <span>
#include <string>
#include <vector>

#if __has_include(<libusb-1.0/libusb.h>)
#include <libusb-1.0/libusb.h>
#else
#include <libusb.h>
#endif

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

namespace radar::drivers {

/**
 * @brief Runtime settings for minimal LibreVNA acquisition.
 */
struct LibreVnaMinimalDriverSettings {
    config::DriverMode mode = config::DriverMode::Mock;
    std::string serial{};
    config::RadarSweepSettings sweep{};
    float mock_signal_hz = 5'000'000.0F;
};

/**
 * @brief Minimal radar driver that acquires S21 sweeps from LibreVNA.
 *
 * This class intentionally keeps scope narrow: open/close transport and
 * acquire one sweep. Full device configuration is expected to be done by the
 * Python layer before this process starts.
 */
class LibreVnaMinimalDriver final : public RadarDriver {
  public:
    explicit LibreVnaMinimalDriver(LibreVnaMinimalDriverSettings settings);

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

  private:
    /**
     * @brief Raw protocol packet decoded from framed USB stream.
     */
    struct NativePacket {
        std::uint8_t packet_type = 0;
        std::vector<std::uint8_t> payload{};
    };

    [[nodiscard]] auto acquire_mock() -> SweepTrace;
    [[nodiscard]] auto acquire_native() -> SweepTrace;

    void open_native();
    void close_native();

    void send_packet(std::uint8_t packet_type, std::span<const std::uint8_t> payload, bool require_ack);
    void send_packet_no_payload(std::uint8_t packet_type, bool require_ack);
    void wait_for_ack(std::chrono::steady_clock::time_point deadline);
    [[nodiscard]] auto wait_for_packet(std::uint8_t expected_type, std::chrono::steady_clock::time_point deadline)
        -> NativePacket;
    void pump_usb(std::chrono::steady_clock::time_point deadline);
    void decode_frames_from_buffer();

    [[nodiscard]] auto pop_packet(std::uint8_t packet_type) -> std::optional<NativePacket>;
    [[nodiscard]] static auto encode_frame(std::uint8_t packet_type, std::span<const std::uint8_t> payload)
        -> std::vector<std::uint8_t>;
    [[nodiscard]] static auto decode_vna_datapoint_s21(
        std::span<const std::uint8_t> payload,
        std::uint32_t& point_number_out,
        float& frequency_out,
        ipc::Complex32& s21_out
    ) -> bool;
    [[nodiscard]] static auto crc32(std::span<const std::uint8_t> data) -> std::uint32_t;
    void validate_device_info_payload(std::span<const std::uint8_t> payload) const;

    LibreVnaMinimalDriverSettings settings_{};
    bool is_open_ = false;
    std::uint64_t sweep_index_ = 0;

    libusb_context* usb_context_ = nullptr;
    libusb_device_handle* usb_handle_ = nullptr;
    bool interface_claimed_ = false;

    std::vector<std::uint8_t> rx_buffer_{};
    std::deque<NativePacket> packet_queue_{};

    std::uint16_t protocol_version_ = 0;
    std::uint8_t device_num_ports_ = 0;
};

}  // namespace radar::drivers
