#include <lcameraBuffParams.h>
#include <gtest/gtest.h>
#include <support/exceptionAssertions.h>
#include <user/deviceAttachmentSpec.h>

namespace smo {
namespace stim_buff {
namespace lcamera_buff {
namespace {

device::DeviceAttachmentSpec makeSpecWithParams(
	std::vector<std::pair<std::string, std::string>> params)
{
	device::DeviceAttachmentSpec spec;
	spec.stimBuffApi = "lcameraBuff";
	spec.provider = "lcameraDev";
	spec.stimBuffApiParams = std::move(params);
	return spec;
}

TEST(LcameraBuffParamsTest, DimWidthHeightSynonymsParseExplicitResolution)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"dim-w", "640"},
		{"dimension-h", "480"},
		{"colour-space", "yuv"},
	});

	const LcameraBuffParsedParams parsed = parseLcameraBuffParams(spec);

	EXPECT_EQ(parsed.width, 640u);
	EXPECT_EQ(parsed.height, 480u);
	EXPECT_EQ(
		parsed.colourSpace,
		lcamera_dev::LcameraDevColourSpace::Yuv);
	EXPECT_FALSE(parsed.fullPlanarIsOptional);
}

TEST(LcameraBuffParamsTest, VerticalResolutionShorthand480p)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"v-res", "480p"},
		{"colour-space", "yuv"},
		{"opt-planar", ""},
	});

	const LcameraBuffParsedParams parsed = parseLcameraBuffParams(spec);

	EXPECT_EQ(parsed.width, 640u);
	EXPECT_EQ(parsed.height, 480u);
	EXPECT_TRUE(parsed.fullPlanarIsOptional);
}

TEST(LcameraBuffParamsTest, OptPlanarSynonymEmptyValueMeansTrue)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"v-res", "480p"},
		{"full-planar-is-optional", ""},
	});

	EXPECT_TRUE(parseLcameraBuffParams(spec).fullPlanarIsOptional);
}

TEST(LcameraBuffParamsTest, OptPlanarExplicitFalseDisables)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"dim-w", "640"},
		{"dim-h", "480"},
		{"opt-planar", "false"},
	});

	EXPECT_FALSE(parseLcameraBuffParams(spec).fullPlanarIsOptional);
}

TEST(LcameraBuffParamsTest, OptPlanarAbsentDefaultsFalse)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"v-res", "480p"},
	});

	EXPECT_FALSE(parseLcameraBuffParams(spec).fullPlanarIsOptional);
}

TEST(LcameraBuffParamsTest, MixedResolutionGroupsThrow)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"v-res", "480p"},
		{"dim-w", "640"},
	});

	try {
		parseLcameraBuffParams(spec);
		FAIL() << "Expected runtime_error";
	}
	catch (const std::runtime_error& exception)
	{
		sscl::tests::expectExceptionMessageContains(
			exception,
			"cannot be combined");
	}
}

TEST(LcameraBuffParamsTest, UnsupportedColourSpaceThrows)
{
	device::DeviceAttachmentSpec spec = makeSpecWithParams({
		{"v-res", "480"},
		{"colour-space", "rgb"},
	});

	EXPECT_THROW(parseLcameraBuffParams(spec), std::runtime_error);
}

TEST(LcameraBuffParamsTest, ToCameraModeRequestCopiesFields)
{
	LcameraBuffParsedParams parsed;
	parsed.width = 1280;
	parsed.height = 720;
	parsed.fullPlanarIsOptional = true;

	const lcamera_dev::LcameraDevCameraModeRequest request =
		toCameraModeRequest(parsed);

	EXPECT_EQ(request.width, 1280u);
	EXPECT_EQ(request.height, 720u);
	EXPECT_TRUE(request.fullPlanarIsOptional);
}

} // namespace
} // namespace lcamera_buff
} // namespace stim_buff
} // namespace smo
