#pragma once

#include "xmsdk_export.h"
#include "pixelFormat.h"
#include <vector>
#include <cstdint>
#include <memory>
#include <string>

namespace xavia::sdk
{
  /**
   * \brief Metadata struct containing general information for each camera image
   * 
   * This struct contains information such as frame numbers, timestamps,
   * and image dimensions.
   */
  struct ImageMetaData
  {
    std::uint64_t frameTimeStampUs{0};     ///< Posix timestamp in us of frame acquisition.
    std::uint64_t receivedTimeStampUs{0};  ///< Posix timestamp in us when data is received by the SDK.
    std::uint32_t frameNumber{0};          ///< Monotonically increasing counter. Unique for each frame acquired by the camera.
    std::uint32_t width{0};                ///< Image width in pixels.
    std::uint32_t height{0};               ///< Image height in pixels.
    xavia::sdk::PixelFormat pixelFormat{xavia::sdk::PixelFormat::Unknown}; ///< Pixel format identifier.
  };

  /**
   * \brief The interface of the image object.
   * 
   * Returned by the image callback, each image object represents
   * a single frame from the camera.
   * 
   * The image object contains the pixel data, metadata such as timestamps
   * and frame numbers, and dimensions.
   */
  class IImage
  {
  public:
    virtual ~IImage() = default;

    /**
     * \brief Get the width of the image
     * \returns Width in pixels.
     */
    virtual std::uint32_t GetWidth() const = 0;

    /**
     * \brief Get the height of the image
     * \returns Height in pixels.
     */
    virtual std::uint32_t GetHeight() const = 0;

    /**
     * \brief Get the pixel format
     * \returns Pixel format identifier (0=RGB8, 1=BGR8, 2=Mono8, etc.).
     */
    virtual xavia::sdk::PixelFormat GetPixelFormat() const = 0;

    /**
     * \brief Get the raw pixel data
     * \returns const reference to the vector of pixel data.
     * The size and interpretation depend on width, height, and pixel format.
     */
    virtual const std::vector<std::uint8_t>& GetPixelData() const = 0;

    /**
     * \brief Get the metadata of the current image
     * \returns const reference to the metadata struct, \see ImageMetaData.
     */
    virtual const ImageMetaData& GetMetaData() const = 0;

    /**
     * \brief Convert this image object into binary data.
     * 
     * \returns vector of bytes that hold the image information
     * 
     * Use this to efficiently store the image in the XenomatiX proprietary format.
     * When dumping to disk, it is customary to use the .ximg extension.
     * 
     * \see Deserialize() functions to read the information back.
     */
    virtual std::vector<std::uint8_t> Serialize() = 0;

    /**
     * \brief Fill this image object from binary data.
     * 
     * \param[in] data vector of bytes that hold the image information.
     * 
     * Use this to efficiently load the image from the XenomatiX proprietary format.
     * The opposite of the Serialize() function.
     *
     * \note although it is acceptable to provide too many bytes, it is best that
     * size matches exactly the required size. This function will keep an internal
     * copy of the provided data.
     */
    virtual void Deserialize(const std::vector<std::uint8_t>& data) = 0;

    /**
     * \brief Fill this image object from binary data.
     * 
     * \param[in] pBuffer pointer to the start of the binary data.
     * \param[in] size number of bytes to read from the buffer.
     * 
     * Use this to efficiently load the image from the XenomatiX proprietary format.
     * The opposite of the Serialize() function.
     * 
     * \note although it is acceptable to provide too many bytes, it is best that
     * size matches exactly the required size. This function will keep an internal
     * copy of the provided data.
     */
    virtual void Deserialize(const std::uint8_t* pBuffer, const std::size_t size) = 0;

    /**
     * \brief Save the image as an 8 bit jpeg file.
     * \param[in] filePath path to the output jpeg file.
     * \param[in] quality JPEG quality (0-100) (default 90).
     * \param[in] chromaticSubsampling Enable or disable chromatic subsampling (default false).
     * 
     * JPEG saving is only supported for RGB8 format.
     * If the image is in Bayer format, it will be demosaiced before saving. If the
     * image was converted to RGB12, it will be scaled down to 8 bits per channel.
     */
    virtual void SaveAsJpeg(const std::wstring& filePath, 
        const int quality = 90,
        const bool chromaticSubsampling = false
      ) const = 0;
  };

  /**
   * \brief Static image factory function.
   * 
   * \returns an empty image object.
   * 
   * Use this function to create your own, empty image objects.
   * Best used in combination with Deserialize to read images from e.g.
   * the disk.
   */
  std::unique_ptr<IImage> XMSDK_EXPORT CreateImage();
} // namespace xavia::sdk
