#pragma once

#include <span>
#include <string>
#include <unordered_map>
#include <vector>

#include "shared_types.hpp"

namespace radar::preprocessing {

class CalibratorInterface;

struct ChannelTrace {
    std::vector<float> frequency_hz{};
    std::vector<ipc::Complex32> samples{};
};

class S21CalibrationBundle {
  public:
    void load(const std::string& path);

    [[nodiscard]] auto is_enabled() const noexcept -> bool;
    void validate_combos(const std::vector<ipc::ComboKey>& combos) const;
    [[nodiscard]] auto apply(
        const ipc::ComboKey& combo,
        std::span<const float> frequency_hz,
        const std::vector<ipc::Complex32>& measured,
        const CalibratorInterface& calibrator
    ) const -> std::vector<ipc::Complex32>;

  private:
    [[nodiscard]] auto resolve(const ipc::ComboKey& combo) const -> const ChannelTrace&;

    std::unordered_map<ipc::ComboKey, ChannelTrace, ipc::ComboKeyHash> traces_by_combo_{};
};

class S21ReferenceBundle {
  public:
    void load(const std::string& path);

    [[nodiscard]] auto is_enabled() const noexcept -> bool;
    void validate_combos(const std::vector<ipc::ComboKey>& combos) const;
    [[nodiscard]] auto resolve(const ipc::ComboKey& combo) const -> const ChannelTrace&;

  private:
    std::unordered_map<ipc::ComboKey, ChannelTrace, ipc::ComboKeyHash> traces_by_combo_{};
};

class S11CalibrationBundle {
  public:
    struct Coefficients {
        std::vector<float> frequency_hz{};
        std::vector<ipc::Complex32> directivity{};
        std::vector<ipc::Complex32> source_match{};
        std::vector<ipc::Complex32> reflection_tracking{};
    };

    void load(
        const std::string& open_path,
        const std::string& short_path,
        const std::string& load_path
    );

    [[nodiscard]] auto is_enabled() const noexcept -> bool;
    void validate_combos(const std::vector<ipc::ComboKey>& combos) const;
    [[nodiscard]] auto apply(
        const ipc::ComboKey& combo,
        std::span<const float> frequency_hz,
        const std::vector<ipc::Complex32>& measured
    ) const -> std::vector<ipc::Complex32>;

  private:
    [[nodiscard]] auto resolve(const ipc::ComboKey& combo) const -> const Coefficients&;

    std::unordered_map<ipc::ComboKey, Coefficients, ipc::ComboKeyHash> coefficients_by_combo_{};
};

class S11ReferenceBundle {
  public:
    void load(const std::string& path);

    [[nodiscard]] auto is_enabled() const noexcept -> bool;
    void validate_combos(const std::vector<ipc::ComboKey>& combos) const;
    [[nodiscard]] auto resolve(const ipc::ComboKey& combo) const -> const ChannelTrace&;

  private:
    std::unordered_map<ipc::ComboKey, ChannelTrace, ipc::ComboKeyHash> traces_by_combo_{};
};

}  // namespace radar::preprocessing
