#ifndef LCAMERA_DEV_CAMERA_SESSION_H
#define LCAMERA_DEV_CAMERA_SESSION_H

#include <cameraIdentity.h>
#include <cameraModeRequest.h>
#include <libcamera/camera.h>
#include <memory>
#include <optional>
#include <stdexcept>
#include <spinscale/co/coQutex.h>
#include <spinscale/co/invokers.h>
#include <spinscale/sharedResourceGroup.h>

namespace lcamera_dev {

struct CameraSessionResources
{
	CameraSessionResources(
		const CameraIdentityRecord& identity,
		const std::shared_ptr<libcamera::Camera>& camera)
	: identity(identity), camera(camera)
	{}

	int refcount = 0;
	CameraIdentityRecord identity;
	std::shared_ptr<libcamera::Camera> camera;

	bool isStreaming = false;
	LcameraDevCameraModeRequest configuredRequest;
	std::optional<LcameraDevConfiguredCameraMode> configuredMode;
	std::shared_ptr<libcamera::CameraConfiguration> heldConfiguration;
	int libcameraConfigureCallCount = 0;
};

class CameraSession
{
public:
	CameraSession(
		const CameraIdentityRecord& identity,
		const std::shared_ptr<libcamera::Camera>& camera);

	const CameraIdentityRecord& getIdentityRecord() const
		{ return s.rsrc.identity; }

	const std::shared_ptr<libcamera::Camera>& getCamera() const
		{ return s.rsrc.camera; }

	bool isModeConfigured() const
		{ return s.rsrc.configuredMode.has_value(); }

	const LcameraDevConfiguredCameraMode& getConfiguredMode() const
	{
		if (!s.rsrc.configuredMode.has_value())
		{
			throw std::logic_error(
				"lcameraDev: session mode is not configured");
		}

		return *s.rsrc.configuredMode;
	}

	int getLibcameraConfigureCallCount() const
		{ return s.rsrc.libcameraConfigureCallCount; }

	void incrementRefcount();
	bool decrementRefcount();

	sscl::co::ViralNonPostingInvoker<LcameraDevConfiguredCameraMode>
	configureSessionModeCReq(const LcameraDevCameraModeRequest& request);

	sscl::SharedResourceGroup<sscl::co::CoQutex, CameraSessionResources> s;
};

} // namespace lcamera_dev

#endif // LCAMERA_DEV_CAMERA_SESSION_H
