#pragma once

#include <cstdint>
#include <mutex>
#include <optional>
#include <string>
#include <vector>

#include <nlohmann/json.hpp>
#include <opencv2/opencv.hpp>

#include "detector/geometry/calibration/geometry_calibration.hpp"

class DetectionEngine
{
public:
    struct Event
    {
        std::string score;
        cv::Point2f position{-1.0F, -1.0F};
        float confidence = 0.0F;
        int camera_index = -1;
        int processing_time_ms = 0;
        std::int64_t timestamp = 0;
    };

    DetectionEngine(int width, int height);

    bool calibrate(const std::vector<cv::Mat> &frames, std::string &error);
    void clearCalibration();
    bool calibrated() const;
    std::optional<Event> process(const std::vector<cv::Mat> &frames);
    cv::Mat drawOverlay(std::size_t camera_index, const cv::Mat &frame) const;
    nlohmann::json calibrationInfo() const;

private:
    static bool isPointInEllipse(cv::Point2f point, const cv::RotatedRect &ellipse);
    static std::string scoreAtPoint(cv::Point2f pixel, const DartboardCalibration &calibration);
    static std::int64_t nowMillis();

    int width_;
    int height_;
    mutable std::mutex mutex_;
    bool calibrated_ = false;
    std::vector<DartboardCalibration> calibrations_;
    std::vector<cv::Mat> backgrounds_;
};

