#pragma once

#include <array>
#include <atomic>
#include <cstdint>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

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

class CameraManager
{
public:
    static constexpr std::size_t CameraCount = 3;

    struct View
    {
        double zoom = 1.0;
        double pan_x = 0.0;
        double pan_y = 0.0;
    };

    explicit CameraManager(int width = 1280, int height = 720, int fps = 15);
    ~CameraManager();

    bool configureSources(const std::array<std::string, CameraCount> &sources, std::string &error);
    bool updateView(std::size_t index, const View &view, std::string &error);
    void stop();

    cv::Mat frame(std::size_t index, bool apply_view = true) const;
    std::vector<cv::Mat> frames(bool apply_view = true) const;
    std::vector<cv::Mat> averageFrames(int samples, int interval_ms, std::string &error) const;
    bool ready() const;

    nlohmann::json status() const;
    nlohmann::json availableSources() const;
    std::array<std::string, CameraCount> sources() const;

    int width() const { return width_; }
    int height() const { return height_; }
    int fps() const { return fps_; }

private:
    static bool isVideoFile(const std::string &source);
    static cv::Mat applyDigitalView(const cv::Mat &input, const View &view, int output_width, int output_height);
    static std::string deviceLabel(const std::string &device_path);

    void startCapture();
    void stopCapture();
    void captureLoop();

    int width_;
    int height_;
    int fps_;

    mutable std::mutex mutex_;
    std::array<std::string, CameraCount> sources_{};
    std::array<View, CameraCount> views_{};
    std::array<cv::Mat, CameraCount> latest_frames_{};
    std::array<bool, CameraCount> online_{};
    std::array<std::string, CameraCount> errors_{};
    std::array<std::uint64_t, CameraCount> sequences_{};

    std::array<cv::VideoCapture, CameraCount> captures_{};
    std::atomic<bool> running_{false};
    std::thread capture_thread_;
};

