#pragma once

#include <cstdint>

namespace td {
namespace utils {
namespace shape {

class Point {
private:
	float m_X, m_Y;
public:
	Point() : m_X(0), m_Y(0) {}
	Point(float x, float y) : m_X(x), m_Y(y) {}

	float GetX() const { return m_X; }
	float GetY() const { return m_Y; }

	void SetX(float x) { m_X = x; }
	void SetY(float y) { m_Y = y; }

	float Distance(const Point& point) const;
	float DistanceSquared(const Point& point) const;
};

class Circle;

class Rectangle {
private:
	Point m_Center;
	float m_Width, m_Height;
public:
	Rectangle() {}

	const Point& GetCenter() const { return m_Center; }
	float GetCenterX() const { return m_Center.GetX(); }
	float GetCenterY() const { return m_Center.GetY(); }

	float GetWidth() const { return m_Width; }
	float GetHeight() const { return m_Height; }

	Point GetTopLeft() const { return { m_Center.GetX() - (m_Width / 2.0f), m_Center.GetY() - (m_Height / 2.0f) }; }
	Point GetBottomRight() const { return { m_Center.GetX() + (m_Width / 2.0f), m_Center.GetY() + (m_Height / 2.0f) }; }

	void SetCenter(const Point& center) { m_Center = center; }
	void SetCenterX(float x) { m_Center.SetX(x); }
	void SetCenterY(float y) { m_Center.SetY(y); }

	void SetSize(float width, float height) { SetWidth(width); SetHeight(height); }
	void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
	Point GetSize() { return { m_Width, m_Height }; }

	void SetWidth(float width) { m_Width = width; }
	void SetHeight(float height) { m_Height = height; }

	bool CollidesWith(const Point& point) const;
	bool CollidesWith(const Rectangle& rect) const;
	bool CollidesWith(const Circle& circle) const;

	// distance from the closest side of the rectangle
	float Distance(const Circle& circle) const;
	float DistanceSquared(const Circle& circle) const;
};

class Circle {
private:
	Point m_Center;
	float m_Radius;
public:
	Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
	Circle() : m_Radius(0) {}

	const Point& GetCenter() const { return m_Center; }
	float GetCenterX() const { return m_Center.GetX(); }
	float GetCenterY() const { return m_Center.GetY(); }

	float GetRadius() const { return m_Radius; }

	void SetCenter(const Point& center) { m_Center = center; }
	void SetCenterX(float x) { m_Center.SetX(x); }
	void SetCenterY(float y) { m_Center.SetY(y); }

	void SetRadius(float radius) { m_Radius = radius; }

	bool CollidesWith(const Point& point) const;
	bool CollidesWith(const Rectangle& rect) const;
	bool CollidesWith(const Circle& circle) const;

	// distance from the closest side of the rectangle
	float Distance(const Rectangle& rect) const;
	float DistanceSquared(const Rectangle& rect) const;
};

} // namespace shape
} // namespace utils 
} // namespace td
