#include "client/render/BulletRenderer.h"

#include "blitz/maths/Maths.h"
#include "blitz/misc/Log.h"
#include "blitz/misc/Test.h"
#include "client/render/Camera.h"
#include "client/render/OpenGL.h"
#include "client/render/loader/GLLoader.h"
#include "client/render/shader/BulletShader.h"
#include <imgui.h>

namespace blitz {
namespace render {

static const float BULLET_DECAY_TIME = 5.0f;

BulletRenderer::BulletRenderer(const Camera& camera) : m_Camera(camera) {
	m_Shader = std::make_unique<shader::BulletShader>();
	blitz_debug_assert(m_Shader->LoadShader());

	m_BulletModel = ModelLoader::LoadModel("cube.glb");
}

BulletRenderer::~BulletRenderer() {}

void BulletRenderer::AddBullet(const Vec3f& origin, float yaw, float pitch, bool firstPersson) {
	static const float TRAIL_LENGHT = 50;

	Vec3f direction = {
		std::cos(yaw) * std::cos(pitch),
		std::sin(pitch),
		std::sin(yaw) * std::cos(pitch),
	};

	Vec3f middle = origin + direction * (TRAIL_LENGHT / 2.0f);

	static const float RotateXClient = 0.0008f;
	static const float RotateYClient = 0.0025f;
	static const float TrailCutClient = 0.4f;

	float rotateX = firstPersson ? RotateXClient : 0.0f;
	float rotateY = firstPersson ? RotateYClient : 0.0f;
	float trailCut = firstPersson ? TrailCutClient : 0.2f;


	Mat4f rotate = maths::Dot(maths::RotateX(-pitch - rotateX), maths::RotateY(yaw + maths::PI / 2 - rotateY));
	Mat4f scale = maths::Scale({0.01f, 0.01f, TRAIL_LENGHT / 2.0f - trailCut});
	Mat4f translate = maths::Translate(middle);

	Mat4f transform = maths::Dot(scale, maths::Dot(rotate, translate));

	Trail trail{transform, BULLET_DECAY_TIME};
	m_Trails.push_back(trail);
}

void BulletRenderer::Update(float delta) {
	for (Trail& trail : m_Trails) {
		trail.m_Decay -= delta;
	}

	for (std::size_t i = 0; i < m_Trails.size(); i++) {
		if (m_Trails[i].m_Decay < 0) {
			m_Trails.erase(m_Trails.begin() + i);
		}
	}

	m_Shader->Start();
	m_Shader->SetProjectionMatrix(m_Camera.GetPerspectiveMatrix());
	m_Shader->SetViewMatrix(m_Camera.GetViewMatrix());
}

void BulletRenderer::Render() {
	m_Shader->Start();

	// un peu frauduleux
	ModelLoader::VaoPtr& vao = m_BulletModel.mVaos[0];

	vao->Bind();
	for (Trail& trail : m_Trails) {
		m_Shader->SetDecay(trail.m_Decay / BULLET_DECAY_TIME);
		m_Shader->SetTransform(trail.m_Transform);
		glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(vao->GetVertexCount()), GL_UNSIGNED_INT, nullptr);
	}
	vao->Unbind();
}

}  // namespace render
}  // namespace blitz
