#include "rive/animation/linear_animation.hpp"
#include "rive/animation/keyed_object.hpp"
#include "rive/animation/keyed_callback_reporter.hpp"
#include "rive/artboard.hpp"
#include "rive/importers/artboard_importer.hpp"
#include "rive/importers/import_stack.hpp"
#include "rive/math/math_types.hpp"
#include <cmath>

using namespace rive;

#ifdef TESTING
int LinearAnimation::deleteCount = 0;
#endif

LinearAnimation::LinearAnimation() {}

LinearAnimation::~LinearAnimation()
{
#ifdef TESTING
    deleteCount++;
#endif
}

StatusCode LinearAnimation::onAddedDirty(CoreContext* context)
{
    StatusCode status = StatusCode::Ok;
    std::vector<size_t> failedKeyedObjects;
    for (size_t i = 0; i < m_KeyedObjects.size(); ++i)
    {
        StatusCode code = m_KeyedObjects[i]->onAddedDirty(context);
        if (code != StatusCode::Ok)
        {
            failedKeyedObjects.push_back(i);
            if (status == StatusCode::Ok || status == StatusCode::MissingObject)
            {
                status = code;
            }
        }
    }

    // Failed keyed objects should not be applied later in animation playback.
    for (auto it = failedKeyedObjects.rbegin(); it != failedKeyedObjects.rend();
         ++it)
    {
        m_KeyedObjects.erase(m_KeyedObjects.begin() + *it);
    }

    // Missing keyed objects are non-fatal at artboard init time.
    return status == StatusCode::MissingObject ? StatusCode::Ok : status;
}

StatusCode LinearAnimation::onAddedClean(CoreContext* context)
{
    StatusCode code;
    for (const auto& object : m_KeyedObjects)
    {
        if ((code = object->onAddedClean(context)) != StatusCode::Ok)
        {
            return code;
        }
    }
    return StatusCode::Ok;
}

void LinearAnimation::addKeyedObject(std::unique_ptr<KeyedObject> object)
{
    m_KeyedObjects.push_back(std::move(object));
}

void LinearAnimation::apply(Artboard* artboard, float time, float mix) const
{
    if (quantize())
    {
        float ffps = (float)fps();
        time = std::floor(time * ffps) / ffps;
    }
    for (const auto& object : m_KeyedObjects)
    {
        object->apply(artboard, time, mix);
    }
}

StatusCode LinearAnimation::import(ImportStack& importStack)
{
    auto artboardImporter =
        importStack.latest<ArtboardImporter>(ArtboardBase::typeKey);
    if (artboardImporter == nullptr)
    {
        return StatusCode::MissingObject;
    }
    artboardImporter->addAnimation(this);
    return Super::import(importStack);
}

float LinearAnimation::startSeconds() const
{
    return (enableWorkArea() ? (float)workStart() : 0.0f) / (float)fps();
}
float LinearAnimation::endSeconds() const
{
    return (float)(enableWorkArea() ? workEnd() : duration()) / (float)fps();
}

float LinearAnimation::startTime() const
{
    return (speed() >= 0) ? startSeconds() : endSeconds();
}
float LinearAnimation::startTime(float multiplier) const
{
    return ((speed() * multiplier) >= 0) ? startSeconds() : endSeconds();
}
float LinearAnimation::endTime() const
{
    return (speed() >= 0) ? endSeconds() : startSeconds();
}
float LinearAnimation::durationSeconds() const
{
    return std::abs(endSeconds() - startSeconds());
}

// Matches Dart modulus:
// https://api.dart.dev/stable/2.19.0/dart-core/double/operator_modulo.html
static float positiveMod(float value, float range)
{
    assert(range > 0.0f);
    return math::positive_mod(value, range);
}

float LinearAnimation::globalToLocalSeconds(float seconds) const
{
    switch (loop())
    {
        case Loop::oneShot:
            return seconds + startTime();
        case Loop::loop:
            return positiveMod(seconds, (durationSeconds())) + startTime();
        case Loop::pingPong:
            float localTime = positiveMod(seconds, (durationSeconds()));
            int direction = ((int)(seconds / (durationSeconds()))) % 2;
            return direction == 0 ? localTime + startTime()
                                  : endTime() - localTime;
    }
    RIVE_UNREACHABLE();
}

void LinearAnimation::reportKeyedCallbacks(KeyedCallbackReporter* reporter,
                                           float secondsFrom,
                                           float secondsTo,
                                           float speedDirection,
                                           bool fromPong) const
{
    float startingTime = startTime(speedDirection);
    bool isAtStartFrame = startingTime == secondsFrom;

    if (!isAtStartFrame || !fromPong)
    {
        for (const auto& object : m_KeyedObjects)
        {
            object->reportKeyedCallbacks(reporter,
                                         secondsFrom,
                                         secondsTo,
                                         isAtStartFrame);
        }
    }
}