#include "pch.h"
#include "Model2D.h"

#include <algorithm>
#include <cmath>
#include <stdexcept>
#include <utility>
#include <set>
#include <stduuid/uuid.h>

#include "util/BoundingBox.h"
#include "util/PhysicsSystem.h"
#include "util/ModelPose.h"
#include "util/AnimationLayer.h"
#include "ModelPart.h"

namespace Vivid2D {

    // ==================== 构造器 ====================

    Model2D::Model2D()
        : m_uuid(generate_new_uuid()),
        m_physics(std::make_unique<util::PhysicsSystem>()),
        m_bounds(std::make_unique<util::BoundingBox>()),
        m_currentPose("default")
    {
        initializeDefaultPose();
    }

    Model2D::Model2D(const std::string& name)
        : Model2D()
    {
        m_name = name;
    }

    Model2D::~Model2D() = default;

    Model2D::Model2D(Model2D&& other) noexcept
        : m_name(std::move(other.m_name)),
        m_version(std::move(other.m_version)),
        m_uuid(other.m_uuid),
        // m_metadata 移除
        m_parts(std::move(other.m_parts)),
        m_partMap(std::move(other.m_partMap)),
        m_rootPart(other.m_rootPart),
        m_meshes(std::move(other.m_meshes)),
        m_textures(std::move(other.m_textures)),
        m_parameters(std::move(other.m_parameters)),
        m_animationLayers(std::move(other.m_animationLayers)),
        m_physics(std::move(other.m_physics)),
        m_needsUpdate(other.m_needsUpdate),
        m_bounds(std::move(other.m_bounds)),
        m_poses(std::move(other.m_poses)),
        m_currentPoseName(std::move(other.m_currentPoseName)),
        m_currentPose(std::move(other.m_currentPose)),
        m_blendTargetPose(std::move(other.m_blendTargetPose)),
        m_blendProgress(other.m_blendProgress),
        m_blendSpeed(other.m_blendSpeed),
        m_lights(std::move(other.m_lights))
    {
        other.m_rootPart = nullptr;
        // 重新构建 m_partMap 以确保指针正确
        m_partMap.clear();
        for (const auto& part : m_parts) {
            m_partMap[part->getName()] = part.get();
        }
        if (!m_parts.empty()) {
            m_rootPart = m_parts[0].get();
        }
        else {
            m_rootPart = nullptr;
        }
    }

    // 移动赋值运算符
    Model2D& Model2D::operator=(Model2D&& other) noexcept {
        if (this != &other) {
            using std::swap;
            swap(m_name, other.m_name);
            swap(m_version, other.m_version);
            swap(m_uuid, other.m_uuid);
            m_name = std::move(other.m_name);
            m_version = std::move(other.m_version);
            m_uuid = other.m_uuid;
            m_parts = std::move(other.m_parts);
            m_partMap = std::move(other.m_partMap);
            m_rootPart = other.m_rootPart;
            m_meshes = std::move(other.m_meshes);
            m_textures = std::move(other.m_textures);
            m_parameters = std::move(other.m_parameters);
            m_animationLayers = std::move(other.m_animationLayers);
            m_physics = std::move(other.m_physics);
            m_needsUpdate = other.m_needsUpdate;
            m_bounds = std::move(other.m_bounds);
            m_poses = std::move(other.m_poses);
            m_currentPoseName = std::move(other.m_currentPoseName);
            m_currentPose = std::move(other.m_currentPose);
            m_blendTargetPose = std::move(other.m_blendTargetPose);
            m_blendProgress = other.m_blendProgress;
            m_blendSpeed = other.m_blendSpeed;
            m_lights = std::move(other.m_lights);
            other.m_rootPart = nullptr;
            Model2D temp(std::move(other));
            swap(*this, temp);
        }
        return *this;
    }

    // ==================== 姿态管理 ====================

    void Model2D::addPose(const util::ModelPose& pose) {
        if (pose.getName().empty()) {
            throw std::invalid_argument("Pose name cannot be empty");
        }
        m_poses.emplace(pose.getName(), pose);
        markNeedsUpdate();
    }

    const util::ModelPose* Model2D::getPose(const std::string& name) const {
        auto it = m_poses.find(name);
        return (it != m_poses.end()) ? &it->second : nullptr;
    }

    void Model2D::applyPose(const std::string& poseName) {
        auto it = m_poses.find(poseName);
        if (it != m_poses.end()) {
            applyPoseInternal(it->second);
            m_currentPoseName = poseName;
            m_currentPose = it->second;
            m_blendProgress = 1.0f;
            markNeedsUpdate();
        }
    }

    void Model2D::blendToPose(const std::string& targetPoseName, float blendTime) {
        auto it = m_poses.find(targetPoseName);
        if (it != m_poses.end()) {
            m_blendTargetPose = it->second;
            m_blendProgress = 0.0f;
            m_blendSpeed = (blendTime > 0.0f) ? 1.0f / blendTime : 10.0f;
            markNeedsUpdate();
        }
    }

    void Model2D::saveCurrentPose(const std::string& poseName) {
        util::ModelPose newPose(poseName);
        captureCurrentPose(newPose);
        addPose(newPose);
    }

    std::set<std::string> Model2D::getPoseNames() const {
        std::set<std::string> names;
        for (const auto& pair : m_poses) {
            names.insert(pair.first);
        }
        return names;
    }

    void Model2D::removePose(const std::string& poseName) {
        if (poseName != "default") {
            m_poses.erase(poseName);
            if (m_currentPoseName == poseName) {
                applyPose("default");
            }
        }
    }

    void Model2D::setPoseBlend(const std::string& poseName, float blendFactor) {
        auto it = m_poses.find(poseName);
        if (it != m_poses.end()) {
            util::ModelPose blendedPose = util::ModelPose::lerp(m_currentPose, it->second, blendFactor, "manual_blend");
            applyPoseInternal(blendedPose);
            markNeedsUpdate();
        }
    }

    // ==================== 光源管理 ====================

    const std::vector<util::LightSource>& Model2D::getLights() const {
        return m_lights;
    }

    void Model2D::addLight(const util::LightSource& light) {
        m_lights.push_back(light);
        markNeedsUpdate();
    }

    void Model2D::removeLight(const util::LightSource& light) {
        auto it = std::remove(this->m_lights.begin(), this->m_lights.end(), light);
        if (it != this->m_lights.end()) {
            this->m_lights.erase(it, this->m_lights.end());
            markNeedsUpdate();
        }
    }

    void Model2D::clearLights() {
        m_lights.clear();
        markNeedsUpdate();
    }

    // ==================== 部件管理 ====================

    std::unique_ptr<ModelPart> Model2D::createPart(const std::string& name) {
        return std::make_unique<ModelPart>(name);
    }

    void Model2D::addPart(std::unique_ptr<ModelPart> part) {
        if (!part) return;

        const std::string& name = part->getName();
        if (m_partMap.count(name)) {
            throw std::invalid_argument("Part already exists: " + name);
        }

        ModelPart* rawPtr = part.get();
        m_parts.push_back(std::move(part));
        m_partMap[name] = rawPtr;

        if (m_rootPart == nullptr) {
            m_rootPart = rawPtr;
        }
    }

    ModelPart* Model2D::getPart(const std::string& name) const {
        auto it = m_partMap.find(name);
        return (it != m_partMap.end()) ? it->second : nullptr;
    }

    const std::map<std::string, ModelPart*>& Model2D::getPartMap() const {
        return m_partMap;
    }

    const std::vector<std::unique_ptr<ModelPart>>& Model2D::getParts() const {
        return m_parts;
    }

    // ==================== 参数管理 ====================

    AnimationParameter* Model2D::createParameter(const std::string& id, float min, float max, float defaultValue) {
        auto [it, inserted] = m_parameters.emplace(std::piecewise_construct,
            std::forward_as_tuple(id),
            std::forward_as_tuple(id, min, max, defaultValue));
        return &it->second;
    }

    AnimationParameter* Model2D::getParameter(const std::string& id) {
        auto it = m_parameters.find(id);
        return (it != m_parameters.end()) ? &it->second : nullptr;
    }

    void Model2D::addParameter(const AnimationParameter& param) {
        m_parameters[param.getId()] = param;
    }

    void Model2D::setParameterValue(const std::string& paramId, float value) {
        if (auto param = getParameter(paramId)) {
            param->setValue(value);
            markNeedsUpdate();
        }
    }

    float Model2D::getParameterValue(const std::string& paramId) const {
        auto it = m_parameters.find(paramId);
        return (it != m_parameters.end()) ? it->second.getValue() : 0.0f;
    }

    const std::map<std::string, AnimationParameter>& Model2D::getParameters() const {
        return m_parameters;
    }

    // ==================== 网格管理 ====================

    std::unique_ptr<Mesh2D> Model2D::createMesh(const std::string& name, const std::vector<float>& vertices,
        const std::vector<float>& uvs, const std::vector<int>& indices) {
        return std::make_unique<Mesh2D>(name, vertices, uvs, indices);
    }

    void Model2D::addMesh(std::unique_ptr<Mesh2D> mesh) {
        m_meshes.push_back(std::move(mesh));
    }

    Mesh2D* Model2D::getMesh(const std::string& name) const {
        for (const auto& mesh : m_meshes) {
            if (mesh->getName() == name) {
                return mesh.get();
            }
        }
        return nullptr;
    }

    const std::vector<std::unique_ptr<Mesh2D>>& Model2D::getMeshes() const {
        return m_meshes;
    }

    // ==================== 纹理管理 ====================

    void Model2D::addTexture(std::shared_ptr<Render::Texture::Texture> texture) {
        if (!texture) {
            throw std::invalid_argument("Texture cannot be null");
        }

        const std::string& textureName = texture->getName();
        if (textureName.empty()) {
            throw std::invalid_argument("Texture name cannot be empty");
        }

        m_textures[textureName] = std::move(texture);
    }

    std::shared_ptr<Render::Texture::Texture> Model2D::getTexture(const std::string& name) const {
        auto it = m_textures.find(name);
        return (it != m_textures.end()) ? it->second : nullptr;
    }

    const std::map<std::string, std::shared_ptr<Render::Texture::Texture>>& Model2D::getTextures() const {
        return m_textures;
    }

    // ==================== 动画层管理 ====================

    std::unique_ptr<util::AnimationLayer> Model2D::createAnimationLayer(const std::string& name) {
        auto layer = std::make_unique<util::AnimationLayer>(name);
        m_animationLayers.push_back(std::move(layer));
        return std::move(m_animationLayers.back());
    }

    const std::vector<std::unique_ptr<util::AnimationLayer>>& Model2D::getAnimationLayers() const {
        return m_animationLayers;
    }

    void Model2D::setAnimationLayers(std::vector<std::unique_ptr<util::AnimationLayer>> animationLayers) {
        m_animationLayers = std::move(animationLayers);
    }

    // ==================== 更新系统 ====================

    void Model2D::update(float deltaTime) {
        updatePoseBlending(deltaTime);

        if (!m_needsUpdate && !m_physics->hasActivePhysics()) {
            return;
        }

        updateParameterDeformations();

        applyCurrentPoseToModel();

        updateHierarchyTransforms();

        updateBoundingBox();

        m_needsUpdate = false;
    }

    void Model2D::updatePoseBlending(float deltaTime) {
        if (m_blendProgress < 1.0f) {
            m_blendProgress += deltaTime * m_blendSpeed;
            if (m_blendProgress >= 1.0f) {
                m_blendProgress = 1.0f;
                m_currentPose = m_blendTargetPose;
                m_currentPoseName = m_blendTargetPose.getName();
            }
            markNeedsUpdate();
        }
    }

    void Model2D::applyCurrentPoseToModel() {
        if (m_blendProgress < 1.0f) {
            util::ModelPose blendedPose = util::ModelPose::lerp(m_currentPose, m_blendTargetPose, m_blendProgress, "blended");
            applyPoseInternal(blendedPose);
        }
        else {
            applyPoseInternal(m_currentPose);
        }
    }

    void Model2D::applyPoseInternal(const util::ModelPose& pose) const {
        for (const auto& pair : pose.getPartPoses()) {
            const std::string& partName = pair.first;
            const util::PartPose& partPose = pair.second;
            if (ModelPart* part = getPart(partName)) {
                part->setPosition(partPose.getPosition());
                part->setRotation(partPose.getRotation());
                part->setScale(partPose.getScale());
                part->setOpacity(partPose.getOpacity());
                part->setVisible(partPose.isVisible());
            }
        }
    }

    void Model2D::captureCurrentPose(util::ModelPose& pose) {
        for (const auto& partPtr : m_parts) {
            const ModelPart& part = *partPtr;
            util::PartPose partPose(
                part.getPosition(),
                part.getRotation(),
                part.getScale(),
                part.getOpacity(),
                part.isVisible(),
                glm::vec3(1.0f, 1.0f, 1.0f)
            );
            pose.setPartPose(part.getName(), partPose);
        }
    }

    void Model2D::initializeDefaultPose() {
        util::ModelPose defaultPose = util::ModelPose::createDefaultPose();
        captureCurrentPose(defaultPose);
        m_poses.emplace("default", defaultPose);
        m_currentPose = defaultPose;
    }

    void Model2D::updateParameterDeformations() {
        for (auto& pair : m_parameters) {
            AnimationParameter& param = pair.second;
            if (param.hasChanged()) {
                applyParameterDeformations(&param);
                param.markClean();
            }
        }
    }

    void Model2D::applyParameterDeformations(AnimationParameter* param) {
        for (const auto& partPtr : m_parts) {
            // 假设 ModelPart::applyParameter(AnimationParameter*) 已实现
            // partPtr->applyParameter(param); 
        }
    }

    void Model2D::updateHierarchyTransforms() {
        if (m_rootPart) {
            m_rootPart->recomputeWorldTransformRecursive();
        }
    }

    void Model2D::updateBoundingBox() {
        if (!m_bounds) {
            m_bounds = std::make_unique<util::BoundingBox>();
        }
        m_bounds->reset();

        for (const auto& partPtr : m_parts) {
            m_bounds->expand(partPtr->getWorldBounds());
        }
    }

    // ==================== 工具方法 ====================

    bool Model2D::isVisible() const {
        return m_rootPart != nullptr && m_rootPart->isVisible();
    }

    void Model2D::setVisible(bool visible) {
        if (m_rootPart) {
            m_rootPart->setVisible(visible);
        }
    }

} // namespace Vivid2D