#pragma once

#include <cstddef>
#include <cstdint>
#include <string>

namespace xavia::sdk
{
  constexpr std::size_t DEFAULT_CAMERA_TIMEOUT_MS = 5000;

  /**
   * \brief Camera object interface
   *
   * This class defines the interface for a camera. It provides methods to start, 
   * stop, and control the camera independently from the lidar sensor.
   *
   * Access the camera via ISensor::GetCamera() which returns nullptr if no camera
   * was configured during sensor build.
   * 
   * \see ISensor::GetCamera()
   * \see SensorFactory for configuring camera during sensor creation
   */
  class ICamera
  {
  public:
    virtual ~ICamera() = default;

    /**
     * \brief Starts the camera streaming
     * \param timeoutMS Timeout in milliseconds for camera to start (optional, default is 5 sec)
     * \throws sdk::exception object if camera fails to start within timeout.
     * 
     * Start means that the camera begins streaming images which will be delivered
     * via the image callback registered on SensorFactory.
     * 
     * It is only valid to call this function if the camera is not already streaming.
     * An exception is thrown if the camera fails to start.
     */
    virtual void Start(const std::size_t& timeoutMS = DEFAULT_CAMERA_TIMEOUT_MS) = 0;

    /**
     * \brief Stop the camera streaming
     * \param timeoutMS Timeout in milliseconds for camera to stop (optional, default is 5 sec)
     * \throws sdk::exception object if camera fails to stop within timeout.
     * 
     * Stop means that the camera stops streaming images and no further callbacks will occur.
     * 
     * It is only valid to call this function if the camera is currently streaming.
     * An exception is thrown if the camera fails to stop.
     */
    virtual void Stop(const std::size_t& timeoutMS = DEFAULT_CAMERA_TIMEOUT_MS) = 0;

    /**
     * \brief Reset camera configuration to default (factory) values
     * 
     * Warning, this will overwrite any configuration settings for:
     * Exposure, gain, triggering, framerate, PixelFormat
     */
    virtual void ResetConfiguration() = 0;

    /**
     * \brief Set the camera exposure time
     * \param exposureTimeUs Exposure time in microseconds
     * \throws sdk::exception object if exposure time cannot be set or is out of valid range.
     * 
     * Sets the exposure time for the camera. The camera will use this exposure time
     * for all subsequent frames. This can be called while the camera is streaming.
     * 
     * Valid range depends on camera hardware. Typical range: 20us - 1000000us (1 second).
     */
    virtual void SetExposureTimeUs(const std::uint32_t exposureTimeUs) = 0;

    /**
     * \brief Get the current camera exposure time
     * \return Current exposure time in microseconds
     * 
     * Returns the currently configured exposure time. This reflects the value
     * set by SetExposureTimeUs or the default if never changed.
     */
    virtual std::uint32_t GetExposureTimeUs() const = 0;

    /**
     * \brief Get the camera identifier
     * \return String identifying the camera (e.g., serial number, model)
     * 
     * Returns a string that uniquely identifies this camera, typically the
     * serial number or model name from the camera hardware.
     */
    virtual std::string GetCameraId() const = 0;

     /**
     * \brief Get the camera identifier, wide format
     * \return String identifying the camera (e.g., serial number, model)
     * 
     * Returns a string that uniquely identifies this camera, typically the
     * serial number or model name from the camera hardware.
     */
    virtual std::wstring GetCameraIdW() const = 0;

    /**
     * \brief Check if camera is currently streaming
     * \return true if camera is streaming, false otherwise
     */
    virtual bool IsStreaming() const = 0;

    /**
     * \brief Check if we have write access to the camera configuration
     * \return true if we have write access, false if not.
     * 
     * Without write access the SDK cannot change any camera settings or start
     * and stop the stream. Write access is provided only to the first client
     * that connects to the camera.
     */
    virtual bool HasWriteAccess() = 0;

//    /**
//     * \brief Attempts to get write access
//     * \brief returns true if we have write access, false if not
//     * 
//     * This function tries to get write access through an application switchover.
//     * This will not always succeed. And even if it succeeds, another client could
//     * try the same technique to get the write access back.
//     */
//    virtual bool TryForceWriteAccess() = 0;

//    /**
//     * \brief Enable multicast streaming for the camera
//     */
//    virtual void EnableMultiCast() = 0;
  };
} // namespace xavia::sdk
