#include "misc/Shapes.h"

#include <algorithm>
#include <cmath>

namespace td {
namespace utils {
namespace shape {

float Point::distance(const Point& point) const {
    return std::sqrt(distanceSquared(point));
}

float Point::distanceSquared(const Point& point) const {
    return (m_X - point.getX()) * (m_X - point.getX()) + (m_Y - point.getY()) * (m_Y - point.getY());
}


bool Rectangle::collidesWith(const Point& point) const {
    return point.getX() > getTopLeft().getX() && point.getX() < getBottomRight().getX() &&
        point.getY() > getTopLeft().getY() && point.getY() < getBottomRight().getY();
}

bool Rectangle::collidesWith(const Rectangle& rect) const {
    Point point1{ rect.getTopLeft().getX(), rect.getTopLeft().getY() };
    Point point2{ rect.getTopLeft().getX(), rect.getBottomRight().getY() };
    Point point3{ rect.getBottomRight().getX(), rect.getTopLeft().getY() };
    Point point4{ rect.getBottomRight().getX(), rect.getBottomRight().getY() };

    if (collidesWith(point1)) return true;
    if (collidesWith(point2)) return true;
    if (collidesWith(point3)) return true;
    if (collidesWith(point4)) return true;

    return false;
}

bool Rectangle::collidesWith(const Circle& circle) const {
    return circle.collidesWith(*this);
}

float Rectangle::distance(const Circle& circle) const {
    return circle.distance(*this);
}

float Rectangle::distanceSquared(const Circle& circle) const {
    return circle.distanceSquared(*this);
}





bool Circle::collidesWith(const Point& point) const {
    return m_Radius * m_Radius > m_Center.distanceSquared(point);
}

bool Circle::collidesWith(const Rectangle& rect) const {
    float distanceSquared_ = distanceSquared(rect);

    return distanceSquared_ < m_Radius* m_Radius;
}

bool Circle::collidesWith(const Circle& circle) const {
    return m_Radius + circle.getRadius() > m_Center.distanceSquared(circle.getCenter());
}

float Circle::distance(const Rectangle& rect) const {
    return std::sqrt(distanceSquared(rect));
}

float Circle::distanceSquared(const Rectangle& rect) const {
    float closestX = std::clamp(m_Center.getX(), rect.getTopLeft().getX(), rect.getBottomRight().getX());
    float closestY = std::clamp(m_Center.getY(), rect.getTopLeft().getY(), rect.getBottomRight().getY());

    float distanceX = m_Center.getX() - closestX;
    float distanceY = m_Center.getY() - closestY;

    return (distanceX * distanceX) + (distanceY * distanceY);
}

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