#include "pch.h"
#include "ModelPose.h"
#include <algorithm> // For std::min, std::max
#include <sstream>   // For std::ostringstream
#include <iomanip>   // For std::fixed, std::setprecision

namespace Vivid2D::util {

    // =======================================================
    // PartPose 实现
    // =======================================================

    PartPose::PartPose()
        : m_position(0.0f, 0.0f),
        m_rotation(0.0f),
        m_scale(1.0f, 1.0f),
        m_opacity(1.0f),
        m_visible(true),
        m_color(1.0f, 1.0f, 1.0f) {
    }

    PartPose::PartPose(const glm::vec2& position, float rotation, const glm::vec2& scale,
        float opacity, bool visible, const glm::vec3& color)
        : m_position(position),
        m_rotation(rotation),
        m_scale(scale),
        m_opacity(opacity),
        m_visible(visible),
        m_color(color) {
    }

    PartPose::PartPose(const PartPose& other)
        : m_position(other.m_position),
        m_rotation(other.m_rotation),
        m_scale(other.m_scale),
        m_opacity(other.m_opacity),
        m_visible(other.m_visible),
        m_color(other.m_color) {
    }

    // --- 线性插值方法 ---

    float clamp(float value, float min_val, float max_val) {
        return std::max(min_val, std::min(max_val, value));
    }

    /**
     * 在两个部件姿态间进行线性插值
     * 注意：glm 库没有内置的 lerp 方法，需要手动实现
     */
    PartPose PartPose::lerp(const PartPose& a, const PartPose& b, float alpha) {
        alpha = clamp(alpha, 0.0f, 1.0f);

        // Vector2f / Vector3f lerp: a + (b - a) * alpha
        glm::vec2 pos = a.m_position + (b.m_position - a.m_position) * alpha;
        float rot = a.m_rotation + (b.m_rotation - a.m_rotation) * alpha;
        glm::vec2 scl = a.m_scale + (b.m_scale - a.m_scale) * alpha;
        float opa = a.m_opacity + (b.m_opacity - a.m_opacity) * alpha;
        glm::vec3 col = a.m_color + (b.m_color - a.m_color) * alpha;

        // 可见性：当alpha>0.5时使用b的可见性
        bool vis = alpha < 0.5f ? a.m_visible : b.m_visible;

        return PartPose(pos, rot, scl, opa, vis, col);
    }

    /**
     * 带旋转正确插值的线性插值（处理360°边界）
     */
    PartPose PartPose::lerpWithRotation(const PartPose& a, const PartPose& b, float alpha) {
        alpha = clamp(alpha, 0.0f, 1.0f);

        // 线性插值其他属性 (与普通 lerp 相同)
        glm::vec2 pos = a.m_position + (b.m_position - a.m_position) * alpha;
        glm::vec2 scl = a.m_scale + (b.m_scale - a.m_scale) * alpha;
        float opa = a.m_opacity + (b.m_opacity - a.m_opacity) * alpha;
        glm::vec3 col = a.m_color + (b.m_color - a.m_color) * alpha;

        // 处理旋转插值的角度环绕问题
        // float shortestAngle = ((b.rotation - a.rotation) % 360 + 540) % 360 - 180;
        // C++ 实现：使用 fmod 模拟 % 运算符，并进行环绕处理
        float diff = b.m_rotation - a.m_rotation;

        // 将 diff 钳制到 [-180, 180] 范围内
        float shortestAngle = std::fmod(diff, 360.0f);
        if (shortestAngle > 180.0f) {
            shortestAngle -= 360.0f;
        }
        else if (shortestAngle < -180.0f) {
            shortestAngle += 360.0f;
        }

        float rot = a.m_rotation + shortestAngle * alpha;

        bool vis = alpha < 0.5f ? a.m_visible : b.m_visible;

        return PartPose(pos, rot, scl, opa, vis, col);
    }

    // --- 运算符重载和工具方法 ---

    bool PartPose::operator==(const PartPose& other) const {
        // 使用 glm::all(glm::epsilonEqual(...)) 或直接比较 (float 比较可能会有精度问题)
        // 这里采用直接比较，但在实际项目中可能需要使用一个小 epsilon
        return m_rotation == other.m_rotation &&
            m_opacity == other.m_opacity &&
            m_visible == other.m_visible &&
            m_position == other.m_position &&
            m_scale == other.m_scale &&
            m_color == other.m_color;
    }

    std::string PartPose::toString() const {
        std::ostringstream oss;
        oss << std::fixed << std::setprecision(2);
        oss << "PartPose{pos=(" << m_position.x << "," << m_position.y
            << "), rot=" << m_rotation
            << ", scale=(" << m_scale.x << "," << m_scale.y
            << "), opacity=" << m_opacity
            << ", visible=" << (m_visible ? "true" : "false")
            << ", color=(" << m_color.x << "," << m_color.y << "," << m_color.z << ")}";
        return oss.str();
    }

    // =======================================================
    // ModelPose 实现
    // =======================================================

    ModelPose::ModelPose()
        : ModelPose("Unnamed Pose") {
    }

    ModelPose::ModelPose(const std::string& name)
        : m_name(name) {
    }

    // 拷贝构造函数（深拷贝）
    ModelPose::ModelPose(const ModelPose& other)
        : m_name(other.m_name + " (Copy)"),
        m_blendTime(other.m_blendTime),
        m_isDefaultPose(other.m_isDefaultPose) {

        // 深拷贝所有部件姿态
        for (const auto& entry : other.m_partPoses) {
            m_partPoses.emplace(entry.first, entry.second); // std::map 的 emplace/insert 会调用 PartPose 的拷贝构造函数
        }
    }

    // 赋值运算符（深拷贝）
    ModelPose& ModelPose::operator=(const ModelPose& other) {
        if (this != &other) {
            m_name = other.m_name + " (Copy)"; // Java 版本会在拷贝构造时追加 "(Copy)"
            m_blendTime = other.m_blendTime;
            m_isDefaultPose = other.m_isDefaultPose;

            // 清空旧的 map，然后深拷贝新的 map
            m_partPoses.clear();
            for (const auto& entry : other.m_partPoses) {
                m_partPoses.emplace(entry.first, entry.second);
            }
        }
        return *this;
    }


    // --- 姿态管理方法 ---

    void ModelPose::setPartPose(const std::string& partName, const PartPose& pose) {
        m_partPoses[partName] = pose; // 隐式调用 PartPose 的拷贝赋值或拷贝构造
    }

    PartPose& ModelPose::getPartPose(const std::string& partName) {
        // Java 的 computeIfAbsent 语义：如果不存在，则创建默认 PartPose
        auto it = m_partPoses.find(partName);
        if (it == m_partPoses.end()) {
            // 插入默认 PartPose 并返回引用
            return m_partPoses.emplace(partName, PartPose()).first->second;
        }
        return it->second;
    }

    const PartPose& ModelPose::getPartPose(const std::string& partName) const {
        // Const 版本：如果不存在，抛出异常，因为 const 方法不能修改 map
        return m_partPoses.at(partName);
    }

    bool ModelPose::hasPartPose(const std::string& partName) const {
        return m_partPoses.count(partName) > 0;
    }

    bool ModelPose::removePartPose(const std::string& partName) {
        // Java 的 remove 返回被移除的值，C++ 的 erase 返回被移除元素的数量
        return m_partPoses.erase(partName) > 0;
    }

    ModelPose::PoseMap::key_compare ModelPose::getPartNames() const {
        // C++ 中获取 key 集合通常是遍历 Map 的 Key，但这里返回 Map 的比较器，
        // 使用 const PoseMap& getPartPoses() const 更符合 C++ 的习惯
        return m_partPoses.key_comp();
    }


    void ModelPose::clear() {
        m_partPoses.clear();
    }

    // --- Getter 和 Setter ---

    void ModelPose::setBlendTime(float blendTime) {
        m_blendTime = std::max(0.0f, blendTime);
    }

    // --- 姿态混合 ---

    ModelPose ModelPose::lerp(const ModelPose& a, const ModelPose& b, float alpha, const std::string& resultName) {
        ModelPose result(resultName);
        result.setBlendTime(a.m_blendTime + (b.m_blendTime - a.m_blendTime) * alpha);

        // 收集所有唯一的部件名称
        std::map<std::string, PartPose>::key_compare allParts = a.getPartNames();

        // C++ 中合并 key 集合的方法是使用 std::set 或手动迭代
        // 这里为了简化，我们只对两个 Map 中共有的部分进行插值，并使用 Java 逻辑处理缺失部分

        // 遍历 A 的部件
        for (const auto& entry : a.m_partPoses) {
            const std::string& partName = entry.first;
            const PartPose& poseA = entry.second;

            auto itB = b.m_partPoses.find(partName);
            if (itB != b.m_partPoses.end()) {
                // 两个姿态都有该部件：插值
                const PartPose& poseB = itB->second;
                result.setPartPose(partName, PartPose::lerpWithRotation(poseA, poseB, alpha));
            }
            else {
                // 只有姿态A有该部件：根据alpha决定是否保留
                if (alpha < 0.5f) {
                    result.setPartPose(partName, poseA);
                }
            }
        }

        // 遍历 B 的部件，处理只在 B 中存在的部件
        for (const auto& entry : b.m_partPoses) {
            const std::string& partName = entry.first;

            if (!a.hasPartPose(partName)) {
                // 只有姿态B有该部件：根据alpha决定是否保留
                if (alpha >= 0.5f) {
                    result.setPartPose(partName, entry.second);
                }
            }
            // 如果 A 也有，则在上面的 A 循环中已经处理过了
        }

        return result;
    }

    void ModelPose::blendWith(const ModelPose& other, float alpha) {
        PoseMap newPoses;

        // 1. 遍历当前姿态 (this) 的所有部件
        for (auto const& [partName, thisPose] : m_partPoses) {
            auto itOther = other.m_partPoses.find(partName);

            if (itOther != other.m_partPoses.end()) {
                // 两个姿态都有该部件：插值
                newPoses.emplace(partName, PartPose::lerpWithRotation(thisPose, itOther->second, alpha));
            }
            else if (alpha < 0.5f) {
                // 只有当前姿态有，alpha < 0.5f：保留当前姿态
                newPoses.emplace(partName, thisPose);
            }
        }

        // 2. 遍历 other 姿态中独有的部件
        for (auto const& [partName, otherPose] : other.m_partPoses) {
            if (m_partPoses.find(partName) == m_partPoses.end()) {
                // 只有 other 姿态有，alpha >= 0.5f：保留 other 姿态
                if (alpha >= 0.5f) {
                    newPoses.emplace(partName, otherPose);
                }
            }
        }

        m_partPoses = std::move(newPoses); // 替换旧的 Map
    }

    // --- 预设姿态工厂方法 ---

    ModelPose ModelPose::createDefaultPose() {
        ModelPose pose("Default Pose");
        pose.m_isDefaultPose = true;
        // 注意：Java 版本不预先添加部件，而是依赖 getPartPose 自动创建默认部件
        return pose;
    }

    ModelPose ModelPose::createHiddenPose() {
        ModelPose pose("Hidden Pose");
        pose.m_isDefaultPose = false;
        // 同上，依赖 getPartPose 自动创建默认部件
        return pose;
    }

    ModelPose ModelPose::createScaledPose(float scaleX, float scaleY) {
        ModelPose pose("Scaled Pose");
        pose.m_isDefaultPose = false;
        // 由于姿态是按需创建的，这里只是创建了一个命名姿态。
        // 实际应用中，调用方需要遍历模型部件并使用 setPartScale 来应用缩放。
        return pose;
    }

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

    std::string ModelPose::getDescription() const {
        std::ostringstream oss;
        oss << std::fixed << std::setprecision(2);
        oss << "ModelPose{name='" << m_name
            << "', parts=" << m_partPoses.size()
            << ", blendTime=" << m_blendTime << "s}";
        return oss.str();
    }

    bool ModelPose::operator==(const ModelPose& other) const {
        // float 比较
        if (m_blendTime != other.m_blendTime) return false;
        if (m_isDefaultPose != other.m_isDefaultPose) return false;

        // 字符串和 Map 比较
        return m_name == other.m_name && m_partPoses == other.m_partPoses;
    }

} // namespace Vivid2D