#include <tuple>
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/polygon.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp>
#include "../variants.hpp"
#include "../sprite_data.hpp"
#include "common.hpp"

namespace BGTU::ComputerGraphicsLabWork::Lab1 {
	namespace Variant1 {
		class S1 : public RendererApi::Sprite<Lab1SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
		public:
			void draw(
					BGTU::ComputerGraphicsLabWork::Utilities::ZoomedVoxelPainter<BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame,
					const BGTU::ComputerGraphicsLabWork::Lab1::Lab1SpriteData::ShapeData *data
			) const final {
				Utilities::Shapes::draw_polygon_edge(
						frame,
						{data->neg_rotated(data->radius / 2, 0), data->neg_rotated(data->radius / 2, 90), data->neg_rotated(data->radius / 2, 180), data->neg_rotated(data->radius / 2, 270),},
						2,
						{255, 0, 0}
				);
			}
		};

		class S2 : public RendererApi::Sprite<Lab1SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
		public:
			void draw(
					BGTU::ComputerGraphicsLabWork::Utilities::ZoomedVoxelPainter<BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame,
					const BGTU::ComputerGraphicsLabWork::Lab1::Lab1SpriteData::ShapeData *data
			) const final {
				Utilities::Shapes::draw_polygon_edge(
						frame,
						{
								{data->radius,  0},
								{0,             data->radius},
								{-data->radius, 0},
								{0,             -data->radius}
						},
						3,
						{0, 255, 255}
				);
			}
		};

		class S3 : public RendererApi::Sprite<Lab1SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
		public:
			void draw(
					BGTU::ComputerGraphicsLabWork::Utilities::ZoomedVoxelPainter<BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame,
					const BGTU::ComputerGraphicsLabWork::Lab1::Lab1SpriteData::ShapeData *data
			) const final {
				Utilities::Shapes::draw_circle_edge(
						frame,
						{0, 0},
						data->radius,
						5,
						{0, 127, 255}
				);
			}
		};

		class S4 : public RendererApi::Sprite<Lab1SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
		public:
			void draw(
					BGTU::ComputerGraphicsLabWork::Utilities::ZoomedVoxelPainter<BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame,
					const BGTU::ComputerGraphicsLabWork::Lab1::Lab1SpriteData::ShapeData *data
			) const final {
				Utilities::Shapes::draw_circle_edge(
						frame,
						{0, 0},
						data->radius / (2.0 * std::sqrt(2)),
						1,
						{127, 127, 127}
				);
			}
		};

		class S5 : public RendererApi::Sprite<Lab1SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
		public:
			void draw(
					BGTU::ComputerGraphicsLabWork::Utilities::ZoomedVoxelPainter<BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame,
					const BGTU::ComputerGraphicsLabWork::Lab1::Lab1SpriteData::ShapeData *data
			) const final {
				auto r2 = data->radius / 2;
				Utilities::Shapes::draw_polygon_edge(
						frame,
						{
								{-r2, -r2},
								{-r2, r2},
								{r2,  r2},
								{r2,  -r2}
						},
						3,
						{0, 255, 0}
				);
			}
		};
	}

	variant_sprites variant1 = variant_sprites::make(Variant1::S1{}, Variant1::S2{}, Variant1::S3{}, Variant1::S4{}, Variant1::S5{});
}