#include "rive/constraints/distance_constraint.hpp"
#include "rive/bones/bone.hpp"
#include "rive/artboard.hpp"
#include <algorithm>

using namespace rive;

enum class Mode
{
    Closer = 0,
    Further = 1,
    Exact = 2
};

void DistanceConstraint::constrain(TransformComponent* component)
{
    if (m_Target == nullptr || m_Target->isCollapsed())
    {
        return;
    }

    const Vec2D targetTranslation = m_Target->worldTranslation();
    const Vec2D ourTranslation = component->worldTranslation();

    Vec2D toTarget = ourTranslation - targetTranslation;
    float currentDistance = toTarget.length();

    switch (static_cast<Mode>(modeValue()))
    {
        case Mode::Closer:
            if (currentDistance < distance())
            {
                return;
            }
            break;
        case Mode::Further:
            if (currentDistance > distance())
            {
                return;
            }
            break;
        case Mode::Exact:
            break;
    }
    if (currentDistance < 0.001f)
    {
        return;
    }

    toTarget *= (distance() / currentDistance);

    Mat2D& world = component->mutableWorldTransform();
    Vec2D position = targetTranslation + toTarget;
    position = Vec2D::lerp(ourTranslation, position, strength());
    world[4] = position.x;
    world[5] = position.y;
}

void DistanceConstraint::distanceChanged() { markConstraintDirty(); }

void DistanceConstraint::modeValueChanged() { markConstraintDirty(); }