#include "pch.h"
#include "AnimationLayer.h"

#include "../Model2D.h"
#include "AnimationClip.h"
#include "PhysicsSystem.h"

namespace Vivid2D::util {

    // ==================== AnimationEvent 实现 ====================

    AnimationEvent::AnimationEvent(std::string name, float time, Action action)
        : m_name(std::move(name)), m_time(time), m_action(std::move(action)), m_triggered(false) {}

    void AnimationEvent::trigger() {
        if (!m_triggered && m_action) {
            m_action();
            m_triggered = true;
        }
    }

    void AnimationEvent::reset() {
        m_triggered = false;
    }


    // ==================== AnimationTrack 实现 ====================

    AnimationTrack::AnimationTrack(std::string parameterId)
        : m_parameterId(std::move(parameterId)), m_enabled(true), m_interpolation(InterpolationType::LINEAR) {}

    void AnimationTrack::addKeyframe(float time, float value) {
        addKeyframe(time, value, m_interpolation);
    }

    void AnimationTrack::addKeyframe(float time, float value, InterpolationType interpolation) {
        Keyframe keyframe(time, value, interpolation);

        // 查找插入位置并保持排序
        auto it = std::lower_bound(m_keyframes.begin(), m_keyframes.end(), time, [](const Keyframe& kf, float t) {
            return kf.getTime() < t;
            });
        m_keyframes.insert(it, keyframe);
    }

    float AnimationTrack::sample(float time) const {
        if (m_keyframes.empty()) {
            return 0.0f;
        }

        const auto& lastKf = m_keyframes.back();
        if (time >= lastKf.getTime()) {
            return lastKf.getValue();
        }

        const auto& firstKf = m_keyframes.front();
        if (time <= firstKf.getTime()) {
            return firstKf.getValue();
        }

        // 找到 kf1
        auto kf2_it = std::lower_bound(m_keyframes.begin(), m_keyframes.end(), time, [](const Keyframe& kf, float t) {
            return kf.getTime() < t;
            });

        if (kf2_it == m_keyframes.begin()) {
            return firstKf.getValue(); // 应该被上面的检查捕获
        }

        const Keyframe& kf2 = *kf2_it;
        const Keyframe& kf1 = *std::prev(kf2_it);

        return interpolate(kf1, kf2, time);
    }

    float AnimationTrack::interpolate(const Keyframe& kf1, const Keyframe& kf2, float time) const {
        float duration = kf2.getTime() - kf1.getTime();
        if (duration < 0.0001f) return kf1.getValue();

        float t = (time - kf1.getTime()) / duration;

        switch (kf1.getInterpolation()) {
        case InterpolationType::LINEAR:
            return kf1.getValue() + (kf2.getValue() - kf1.getValue()) * t;
        case InterpolationType::STEP:
            return kf1.getValue();
        case InterpolationType::SMOOTH: {
            float t2 = t * t;
            float t3 = t2 * t;
            // Hermite Blend Function (Ease-in-out)
            return kf1.getValue() * (2 * t3 - 3 * t2 + 1) +
                kf2.getValue() * (-2 * t3 + 3 * t2);
        }
        case InterpolationType::EASE_IN:
            return kf1.getValue() + (kf2.getValue() - kf1.getValue()) * (t * t);
        case InterpolationType::EASE_OUT:
            return kf1.getValue() + (kf2.getValue() - kf1.getValue()) * (1.0f - (1.0f - t) * (1.0f - t));
        default:
            return kf1.getValue();
        }
    }

    AnimationTrack AnimationTrack::copy() const {
        AnimationTrack copy(m_parameterId);
        copy.m_enabled = m_enabled;
        copy.m_interpolation = m_interpolation;
        for (const auto& kf : m_keyframes) {
            copy.m_keyframes.push_back(kf.copy());
        }
        return copy;
    }


    // ==================== AnimationLayer 实现 ====================

    AnimationLayer::AnimationLayer(AnimationLayer&& other) noexcept
        : m_name(std::move(other.m_name)),
        m_uuid(other.m_uuid),
        m_weight(other.m_weight),
        m_enabled(other.m_enabled),
        m_blendMode(other.m_blendMode),
        m_priority(other.m_priority),
        m_tracks(std::move(other.m_tracks)),
        m_clips(std::move(other.m_clips)),
        m_currentClip(other.m_currentClip),
        m_playbackSpeed(other.m_playbackSpeed),
        m_looping(other.m_looping),
        m_currentTime(other.m_currentTime),
        m_playing(other.m_playing),
        m_paused(other.m_paused),
        m_parameterOverrides(std::move(other.m_parameterOverrides)),
        m_eventListeners(std::move(other.m_eventListeners)),
        m_events(std::move(other.m_events))
    {
        other.m_currentClip = nullptr;
    }

    AnimationLayer& AnimationLayer::operator=(AnimationLayer&& other) noexcept {
        if (this != &other) {
            m_name = std::move(other.m_name);
            m_uuid = other.m_uuid;
            m_weight = other.m_weight;
            m_enabled = other.m_enabled;
            m_blendMode = other.m_blendMode;
            m_priority = other.m_priority;
            m_tracks = std::move(other.m_tracks);
            m_clips = std::move(other.m_clips);
            m_currentClip = other.m_currentClip;
            m_playbackSpeed = other.m_playbackSpeed;
            m_looping = other.m_looping;
            m_currentTime = other.m_currentTime;
            m_playing = other.m_playing;
            m_paused = other.m_paused;
            m_parameterOverrides = std::move(other.m_parameterOverrides);
            m_eventListeners = std::move(other.m_eventListeners);
            m_events = std::move(other.m_events);

            other.m_currentClip = nullptr;
        }
        return *this;
    }

    AnimationLayer::AnimationLayer(std::string name)
        : AnimationLayer(std::move(name), 1.0f) {}

    AnimationLayer::AnimationLayer(std::string name, float weight)
        : m_name(std::move(name)),
        m_uuid(generate_new_uuid()),
        m_weight(std::max(0.0f, std::min(1.0f, weight))),
        m_enabled(true),
        m_blendMode(BlendMode::OVERRIDE),
        m_priority(0),
        m_currentClip(nullptr),
        m_playbackSpeed(1.0f),
        m_looping(true),
        m_currentTime(0.0f),
        m_playing(false),
        m_paused(false) {}

    void AnimationLayer::setWeight(float weight) {
        m_weight = std::max(0.0f, std::min(1.0f, weight));
    }

    void AnimationLayer::setPlaybackSpeed(float playbackSpeed) {
        m_playbackSpeed = std::max(0.0f, playbackSpeed);
    }

    // --- 轨道管理 ---

    std::unique_ptr<AnimationTrack> AnimationLayer::addTrack(const std::string& parameterId) {
        auto track = std::make_unique<AnimationTrack>(parameterId);
        AnimationTrack* rawPtr = track.get();
        m_tracks[parameterId] = std::move(track);
        return std::unique_ptr<AnimationTrack>(rawPtr); // 返回一个临时的 unique_ptr 副本，但所有权在 m_tracks
    }

    AnimationTrack* AnimationLayer::getTrack(const std::string& parameterId) const {
        auto it = m_tracks.find(parameterId);
        return (it != m_tracks.end()) ? it->second.get() : nullptr;
    }

    bool AnimationLayer::removeTrack(const std::string& parameterId) {
        return m_tracks.erase(parameterId) > 0;
    }

    bool AnimationLayer::hasTrack(const std::string& parameterId) const {
        return m_tracks.count(parameterId) > 0;
    }

    // --- 剪辑管理 ---

    void AnimationLayer::addClip(AnimationClip* clip) {
        if (clip) {
            m_clips.push_back(clip);
        }
    }

    bool AnimationLayer::removeClip(AnimationClip* clip) {
        auto it = std::remove(m_clips.begin(), m_clips.end(), clip);
        if (it != m_clips.end()) {
            m_clips.erase(it, m_clips.end());
            return true;
        }
        return false;
    }

    void AnimationLayer::playClip(const std::string& clipName) {
        // 假设 AnimationClip 有 getName() 方法
        AnimationClip* clipToPlay = nullptr;
        for (AnimationClip* clip : m_clips) {
            if (clip->getName() == clipName) {
                clipToPlay = clip;
                break;
            }
        }
        if (clipToPlay) {
            playClip(clipToPlay);
        }
        else {
            throw std::invalid_argument("Animation clip not found: " + clipName);
        }
    }

    void AnimationLayer::playClip(AnimationClip* clip) {
        m_currentClip = clip;
        m_currentTime = 0.0f;
        m_playing = true;
        m_paused = false;

        resetEvents(); // 重置事件状态
        notifyAnimationStarted(clip);
    }

    void AnimationLayer::stop() {
        m_playing = false;
        m_paused = false;
        m_currentTime = 0.0f;

        if (m_currentClip) {
            notifyAnimationStopped(m_currentClip);
        }
    }

    void AnimationLayer::pause() {
        if (m_playing && !m_paused) {
            m_paused = true;
            notifyAnimationPaused(m_currentClip);
        }
    }

    void AnimationLayer::resume() {
        if (m_playing && m_paused) {
            m_paused = false;
            notifyAnimationResumed(m_currentClip);
        }
    }

    // --- 更新系统 ---

    void AnimationLayer::update(float deltaTime, Vivid2D::Model2D* model) {
        if (!m_enabled || m_weight <= 0.0f) {
            return;
        }

        // 更新播放时间
        if (m_playing && !m_paused) {
            m_currentTime += deltaTime * m_playbackSpeed;

            // 检查循环/完成
            if (m_currentClip && m_currentTime >= m_currentClip->getDuration()) {
                if (m_looping) {
                    // C++ 中 fmod 可以处理浮点数取模
                    m_currentTime = std::fmod(m_currentTime, m_currentClip->getDuration());
                    notifyAnimationLooped(m_currentClip);
                }
                else {
                    stop();
                    notifyAnimationCompleted(m_currentClip);
                    return;
                }
            }

            // 检查事件
            checkEvents();
        }

        // 应用动画
        applyAnimation(model);
    }

    void AnimationLayer::applyAnimation(Vivid2D::Model2D* model) {
        if (m_currentClip) {
            applyClipAnimation(model);
        }
        else {
            applyTrackAnimation(model);
        }
    }

    void AnimationLayer::applyClipAnimation(Vivid2D::Model2D* model) {
        // 假设 AnimationClip::sample 返回一个 std::map<std::string, float>
        std::map<std::string, float> animatedValues = m_currentClip->sample(m_currentTime);

        for (const auto& entry : animatedValues) {
            const std::string& paramId = entry.first;
            float value = entry.second;

            float finalValue = applyBlending(model, paramId, value);

            model->setParameterValue(paramId, finalValue);
        }
    }

    void AnimationLayer::applyTrackAnimation(Vivid2D::Model2D* model) {
        for (const auto& pair : m_tracks) {
            const AnimationTrack* track = pair.second.get();
            if (track->isEnabled()) {
                float value = track->sample(m_currentTime);
                const std::string& paramId = track->getParameterId();

                float finalValue = applyBlending(model, paramId, value);

                model->setParameterValue(paramId, finalValue);
            }
        }
    }

    float AnimationLayer::applyBlending(Vivid2D::Model2D* model, const std::string& paramId, float newValue) {
        float currentValue = model->getParameterValue(paramId);

        auto overrideIt = m_parameterOverrides.find(paramId);
        if (overrideIt != m_parameterOverrides.end()) {
            return overrideIt->second; // 覆盖模式优先
        }

        switch (m_blendMode) {
        case BlendMode::OVERRIDE:
            return blendOverride(currentValue, newValue);
        case BlendMode::ADDITIVE:
            return blendAdditive(currentValue, newValue);
        case BlendMode::MULTIPLICATIVE:
            return blendMultiplicative(currentValue, newValue);
        case BlendMode::AVERAGE:
            return blendAverage(currentValue, newValue);
        default:
            return newValue;
        }
    }

    float AnimationLayer::blendOverride(float current, float target) {
        return current + (target - current) * m_weight;
    }

    float AnimationLayer::blendAdditive(float current, float target) {
        return current + target * m_weight;
    }

    float AnimationLayer::blendMultiplicative(float current, float target) {
        return current * (1.0f + (target / current - 1.0f) * m_weight); // 假设 target/current 是一个比例因子
    }

    float AnimationLayer::blendAverage(float current, float target) {
        return (current * (1.0f - m_weight)) + (target * m_weight);
    }

    // --- 事件系统 ---

    void AnimationLayer::addEvent(const std::string& eventName, float time, AnimationEvent::Action action) {
        auto event = std::make_unique<AnimationEvent>(eventName, time, std::move(action));
        m_events[eventName].push_back(std::move(event));
    }

    void AnimationLayer::checkEvents() {
        if (!m_currentClip) return;

        for (auto& pair : m_events) {
            for (auto& eventPtr : pair.second) {
                if (!eventPtr->isTriggered() && m_currentTime >= eventPtr->getTime()) {
                    eventPtr->trigger();
                    notifyEventTriggered(eventPtr.get());
                }
            }
        }
    }

    void AnimationLayer::resetEvents() {
        for (auto& pair : m_events) {
            for (auto& eventPtr : pair.second) {
                eventPtr->reset();
            }
        }
    }

    void AnimationLayer::addEventListener(AnimationEventListener* listener) {
        if (listener) {
            m_eventListeners.push_back(listener);
        }
    }

    bool AnimationLayer::removeEventListener(AnimationEventListener* listener) {
        auto it = std::remove(m_eventListeners.begin(), m_eventListeners.end(), listener);
        if (it != m_eventListeners.end()) {
            m_eventListeners.erase(it, m_eventListeners.end());
            return true;
        }
        return false;
    }

    void AnimationLayer::notifyAnimationStarted(AnimationClip* clip) {
        for (auto listener : m_eventListeners) {
            listener->onAnimationStarted(this, clip);
        }
    }
    // ... 其他 notify 函数实现类似 ...
    void AnimationLayer::notifyAnimationStopped(AnimationClip* clip) {
        for (auto listener : m_eventListeners) { listener->onAnimationStopped(this, clip); }
    }
    void AnimationLayer::notifyAnimationPaused(AnimationClip* clip) {
        for (auto listener : m_eventListeners) { listener->onAnimationPaused(this, clip); }
    }
    void AnimationLayer::notifyAnimationResumed(AnimationClip* clip) {
        for (auto listener : m_eventListeners) { listener->onAnimationResumed(this, clip); }
    }
    void AnimationLayer::notifyAnimationCompleted(AnimationClip* clip) {
        for (auto listener : m_eventListeners) { listener->onAnimationCompleted(this, clip); }
    }
    void AnimationLayer::notifyAnimationLooped(AnimationClip* clip) {
        for (auto listener : m_eventListeners) { listener->onAnimationLooped(this, clip); }
    }
    void AnimationLayer::notifyEventTriggered(AnimationEvent* event) {
        for (auto listener : m_eventListeners) { listener->onEventTriggered(this, event); }
    }

    // --- 参数覆盖 ---

    void AnimationLayer::setParameterOverride(const std::string& parameterId, float value) {
        m_parameterOverrides[parameterId] = value;
    }

    void AnimationLayer::clearParameterOverride(const std::string& parameterId) {
        m_parameterOverrides.erase(parameterId);
    }

    void AnimationLayer::clearAllOverrides() {
        m_parameterOverrides.clear();
    }

    // --- 工具方法 ---

    float AnimationLayer::getProgress() const {
        // 假设 AnimationClip::getDuration() 存在
        if (!m_currentClip || m_currentClip->getDuration() == 0.0f) {
            return 0.0f;
        }
        return m_currentTime / m_currentClip->getDuration();
    }

    void AnimationLayer::setProgress(float progress) {
        if (m_currentClip) {
            m_currentTime = progress * m_currentClip->getDuration();
        }
    }

    void AnimationLayer::seek(float time) {
        m_currentTime = std::max(0.0f, time);
        if (m_currentClip) {
            m_currentTime = std::min(m_currentTime, m_currentClip->getDuration());
        }
    }

    AnimationLayer AnimationLayer::copy() const {
        AnimationLayer copy(m_name + "_copy", m_weight);
        copy.m_enabled = m_enabled;
        copy.m_blendMode = m_blendMode;
        copy.m_priority = m_priority;
        copy.m_playbackSpeed = m_playbackSpeed;
        copy.m_looping = m_looping;

        // 拷贝轨道 (深拷贝)
        for (const auto& pair : m_tracks) {
            copy.m_tracks[pair.first] = std::make_unique<AnimationTrack>(pair.second->copy());
        }

        // 拷贝剪辑（浅拷贝，引用）
        copy.m_clips = m_clips;

        // 拷贝参数覆盖
        copy.m_parameterOverrides = m_parameterOverrides;

        return copy;
    }

} // namespace Vivid2D::util