#pragma once

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

#include "shared_types.hpp"

namespace radar::config {

enum class DriverMode {
    Mock,
    Native,
};

enum class SwitchDriverKind {
    H7992,
    HMC349A,
};

struct RadarSweepSettings {
    // Frequency sweep bounds and acquisition settings.
    float start_hz = 1'000'000.0F;
    float stop_hz = 6'000'000'000.0F;
    std::uint32_t points = 501;
    float if_bandwidth_hz = 1'000.0F;
    float power_dbm = -10.0F;
};

struct RadarConfig {
    // Radar device identity and runtime mode.
    std::string model = "librevna";
    std::string serial{};
    std::string remote_host = "127.0.0.1";
    std::uint32_t remote_port = 50209;
    DriverMode driver_mode = DriverMode::Mock;
    float mock_signal_hz = 5'000'000.0F;
    RadarSweepSettings sweep{};
};

struct SwitchConfig {
    // One RF switch attached to a specific radar port.
    std::string name{};
    DriverMode driver_mode = DriverMode::Mock;
    SwitchDriverKind driver_kind = SwitchDriverKind::H7992;
    std::uint32_t radar_port = 0;
    std::uint32_t positions = 4;
    std::uint32_t default_position = 0;
    std::string gpio_chip = "/dev/gpiochip0";
    std::int32_t pin_a = 17;
    std::int32_t pin_b = 27;
    bool invert_logic = false;
};

struct RingEndpointConfig {
    // Shared-memory endpoint geometry.
    std::string name{};
    std::uint32_t capacity = 32;
    std::uint32_t slot_size_bytes = 2U * 1024U * 1024U;
};

struct RingsConfig {
    RingEndpointConfig raw{.name = "/radar_raw"};
    RingEndpointConfig raw_tap{.name = "/radar_raw_tap"};
    RingEndpointConfig preprocessed{.name = "/radar_preprocessed"};
    RingEndpointConfig preprocessed_tap{.name = "/radar_preprocessed_tap"};
    RingEndpointConfig results{.name = "/radar_results"};
};

struct RuntimeConfig {
    // Runtime pacing and behavior flags for C++ workers.
    std::uint32_t settling_ms = 0;
    std::uint32_t idle_sleep_ms = 2;
    bool continuous = true;
    std::string processing_live_config_path = "python_app/runtime/processing_live.json";
};

struct PreprocessAssetConfig {
    std::string set_name{};
    std::string bundle_path{};
};

struct S21PreprocessConfig {
    PreprocessAssetConfig calibration{};
    PreprocessAssetConfig reference{};
};

struct S11CalibrationPreprocessConfig {
    PreprocessAssetConfig open{};
    PreprocessAssetConfig short_standard{};
    PreprocessAssetConfig load{};
};

struct S11PreprocessConfig {
    S11CalibrationPreprocessConfig calibration{};
    PreprocessAssetConfig reference{};
};

struct PreprocessNotchBandConfig {
    float low_hz = 0.0F;
    float high_hz = 0.0F;
};

struct PreprocessNotchConfig {
    bool enabled = false;
    std::vector<PreprocessNotchBandConfig> bands_hz{};
    float taper_width_hz = 40'000'000.0F;
    std::string taper_type = "cosine";
};

struct PreprocessConfig {
    // Channel-specific preprocessing assets selected by Python GUI layer.
    S21PreprocessConfig s21{};
    S11PreprocessConfig s11{};
    PreprocessNotchConfig notch{};
};

struct GprTxGeometry {
    // Transmitter geometry keyed by output switch position. y_m/z_m default to 0 so
    // legacy 1D configs continue to render in the y=0, z=0 plane.
    std::uint32_t output_pos = 0;
    float x_m = 0.0F;
    float y_m = 0.0F;
    float z_m = 0.0F;
};

struct GprRxGeometry {
    // Receiver geometry keyed by input switch position. y_m/z_m default to 0.
    std::uint32_t input_pos = 0;
    float x_m = 0.0F;
    float y_m = 0.0F;
    float z_m = 0.0F;
};

struct GprConfig {
    // Stable collection-level GPR processing settings.
    float relative_permittivity = 1.0F;
    std::vector<GprTxGeometry> tx_geometry{};
    std::vector<GprRxGeometry> rx_geometry{};
};

struct RunConfig {
    // Single configuration object shared by all C++ processes.
    RadarConfig radar{};
    SwitchConfig input_switch{};
    SwitchConfig output_switch{};
    RingsConfig rings{};
    RuntimeConfig runtime{};
    PreprocessConfig preprocess{};
    GprConfig gpr{};
    std::vector<radar::ipc::ComboKey> run_combos{};
};

[[nodiscard]] auto load_run_config(const std::string& path) -> RunConfig;

}  // namespace radar::config
