#include <boostAsioLinkageFix.h>

#include <cameraSession.h>
#include <sessionModeConfigure.h>
#include <stdexcept>

namespace lcamera_dev {

CameraSession::CameraSession(
	const CameraIdentityRecord& identity,
	const std::shared_ptr<libcamera::Camera>& camera)
:	s("lcameraDev::CameraSession", CameraSessionResources{identity, camera})
{}

void CameraSession::incrementRefcount()
{
	++s.rsrc.refcount;
}

bool CameraSession::decrementRefcount()
{
	if (s.rsrc.refcount <= 0)
	{
		throw std::logic_error(
			"lcameraDev: releaseDeviceCReq refcount underflow");
	}

	--s.rsrc.refcount;
	return s.rsrc.refcount == 0;
}

sscl::co::ViralNonPostingInvoker<LcameraDevConfiguredCameraMode>
CameraSession::configureSessionModeCReq(
	const LcameraDevCameraModeRequest& request)
{
	sscl::co::CoQutex::ReleaseHandle sessionGuard =
		co_await s.lock.getAcquireInvocationAndSuspensionPolicy();

	if (s.rsrc.isStreaming)
	{
		throw std::runtime_error(
			"lcameraDev: cannot configure session mode while streaming");
	}

	validateCameraModeRequest(request);

	if (s.rsrc.configuredMode.has_value()
		&& cameraModeRequestsEqual(s.rsrc.configuredRequest, request))
	{
		co_return *s.rsrc.configuredMode;
	}

	if (s.rsrc.configuredMode.has_value())
	{
		throw std::runtime_error(
			"lcameraDev: conflicting camera mode request on configured "
			"session");
	}

	std::shared_ptr<libcamera::CameraConfiguration> heldConfiguration;
	const LcameraDevConfiguredCameraMode resolvedMode =
		configureLibcameraSessionMode(
			s.rsrc.camera,
			request,
			heldConfiguration);

	const ConfigureSessionModeStatus status =
		applyModeRequestToSessionState(
			s.rsrc,
			request,
			resolvedMode,
			heldConfiguration);

	if (status != ConfigureSessionModeStatus::Configured)
	{
		throw std::logic_error(
			"lcameraDev: unexpected configure session mode status");
	}

	co_return *s.rsrc.configuredMode;
}

} // namespace lcamera_dev
