#pragma once

#include <memory>
#include <span>
#include <string>
#include <vector>

#include "calibrator_interface.hpp"
#include "channel_bundle_support.hpp"
#include "shared_types.hpp"

namespace radar::preprocessing {

class CalibrationMaster {
  public:
    // `s21_calibrator` encapsulates the S21 calibration algorithm.
    explicit CalibrationMaster(std::unique_ptr<CalibratorInterface> s21_calibrator);

    // Loads a serialized raw sweep bundle with one S21 calibration standard per combo.
    void load_s21_calibration_bundle(const std::string& path);
    // Loads optional one-port OSL calibration data for S11 from raw sweep bundles.
    void load_s11_calibration_bundle(
        const std::string& open_path,
        const std::string& short_path,
        const std::string& load_path
    );
    // Ensures all runtime combos are present in loaded standards.
    void validate_combos(const std::vector<ipc::ComboKey>& combos) const;
    // Applies both channel calibrations to one measured trace.
    [[nodiscard]] auto apply_to_trace(const ipc::SweepTraceBlock& measured_trace) const -> ipc::SweepTraceBlock;
    [[nodiscard]] auto apply_s21(
        const ipc::ComboKey& combo,
        std::span<const float> frequency_hz,
        const std::vector<ipc::Complex32>& measured_s21
    ) const -> std::vector<ipc::Complex32>;
    [[nodiscard]] auto apply_s11(
        const ipc::ComboKey& combo,
        std::span<const float> frequency_hz,
        const std::vector<ipc::Complex32>& measured_s11
    ) const -> std::vector<ipc::Complex32>;
    [[nodiscard]] auto has_s11_calibration() const noexcept -> bool;

  private:
    std::unique_ptr<CalibratorInterface> s21_calibrator_;
    S21CalibrationBundle s21_calibration_bundle_{};
    S11CalibrationBundle s11_calibration_bundle_{};
};

[[nodiscard]] auto make_s21_through_calibrator() -> std::unique_ptr<CalibratorInterface>;

}  // namespace radar::preprocessing
