#pragma once

#include "fgc/ICameraSource.h"
#include "fgc/Logger.h"

#include <chrono>
#include <string>

namespace fgc {

// Synthetic camera for development without hardware. On trigger() it generates
// a small RGB gradient frame (varying with time so successive captures differ)
// and delivers it to the frame callback.
class MockCameraSource : public ICameraSource {
public:
    explicit MockCameraSource(int count = 1, uint32_t width = 640, uint32_t height = 480)
        : count_(count), width_(width), height_(height) {}

    void open() override { LOG_INFO << "[mock] camera opened (" << count_ << ")"; }
    void close() override {}
    void start() override { started_ = true; LOG_INFO << "[mock] camera acquisition started"; }
    void stop() override { started_ = false; }

    bool trigger() override {
        if (!callback_) return false;
        LOG_TRACE_CAT(LogCat::Camera) << "TX trigger cam0 (mock)";
        Frame f;
        f.width    = width_;
        f.height   = height_;
        f.channels = 3;
        f.cam_id   = 0;
        f.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                             std::chrono::system_clock::now().time_since_epoch())
                             .count();
        f.data.resize(static_cast<size_t>(width_) * height_ * 3);
        const uint8_t phase = static_cast<uint8_t>(f.timestamp_ms);
        for (uint32_t y = 0; y < height_; ++y) {
            for (uint32_t x = 0; x < width_; ++x) {
                size_t i = (static_cast<size_t>(y) * width_ + x) * 3;
                f.data[i + 0] = static_cast<uint8_t>(x + phase);
                f.data[i + 1] = static_cast<uint8_t>(y + phase);
                f.data[i + 2] = phase;
            }
        }
        LOG_TRACE_CAT(LogCat::Camera)
            << "RX frame cam0 " << width_ << 'x' << height_ << ' ' << f.data.size() << "B (mock)";
        ++frames_;
        callback_(f);
        return true;
    }

    void setFrameCallback(FrameCallback cb) override { callback_ = std::move(cb); }
    int  cameraCount() const override { return count_; }

    // Synthetic device info so the expanded camera view renders (and is testable)
    // without hardware. Non-hardware fields (temperature, exposure...) stay at 0.
    std::vector<CameraDeviceInfo> deviceInfo() override {
        std::vector<CameraDeviceInfo> out;
        for (int i = 0; i < count_; ++i) {
            CameraDeviceInfo d;
            d.id               = "MOCK" + std::to_string(i);
            d.model            = "MockCamera";
            d.serial           = "SIM-0000";
            d.streaming        = started_;
            d.width            = width_;
            d.height           = height_;
            d.payload_bytes    = static_cast<long long>(width_) * height_ * 3;
            d.actual_fps       = 1.0;
            d.frames_delivered = (i == 0) ? frames_ : 0;  // only cam0 produces frames
            out.push_back(std::move(d));
        }
        return out;
    }

private:
    int           count_;
    uint32_t      width_;
    uint32_t      height_;
    bool          started_ = false;
    long long     frames_  = 0;
    FrameCallback callback_;
};

}  // namespace fgc
