#include "pch.h"

#include "ModelPart.h"
#include "Mesh2D.h"
#include "AnimationParameter.h"
#include <glm/gtc/matrix_transform.hpp>
#include <algorithm>
#include <stdexcept>


namespace Vivid2D {

    // ==================== 构造函数 ====================

    ModelPart::ModelPart(std::string name) : m_Name(std::move(name)) {
        updateLocalTransform();
        recomputeWorldTransformRecursive();
    }

    // ==================== 拷贝与移动语义 ====================

    void ModelPart::deepCopyFrom(const ModelPart& other) {
        m_Name = other.m_Name;
        // Parent pointer must be set by the new parent after copying
        m_Parent = nullptr;

        m_Meshes.clear();
        for (const auto& mesh : other.m_Meshes) {
            addMesh(std::make_unique<Mesh2D>(*mesh));
        }

        m_Children.clear();
        for (const auto& child : other.m_Children) {
            addChild(std::make_unique<ModelPart>(*child));
        }

        m_Position = other.m_Position;
        m_Rotation = other.m_Rotation;
        m_Scale = other.m_Scale;
        m_LocalTransform = other.m_LocalTransform;
        m_WorldTransform = other.m_WorldTransform;
        m_IsVisible = other.m_IsVisible;
        m_BlendMode = other.m_BlendMode;
        m_Opacity = other.m_Opacity;
        m_Parameters = other.m_Parameters;
        m_TransformDirty = true;
        m_BoundsDirty = true;
    }

    ModelPart::ModelPart(const ModelPart& other) {
        deepCopyFrom(other);
    }

    ModelPart& ModelPart::operator=(const ModelPart& other) {
        if (this != &other) {
            deepCopyFrom(other);
        }
        return *this;
    }

    ModelPart::ModelPart(ModelPart&& other) noexcept = default;
    ModelPart& ModelPart::operator=(ModelPart&& other) noexcept = default;


    // ==================== 私有辅助方法 ====================

    void ModelPart::markTransformDirty() {
        if (!m_TransformDirty) {
            m_TransformDirty = true;
            m_BoundsDirty = true;
            for (auto& child : m_Children) {
                child->markTransformDirty();
            }
        }
    }

    void ModelPart::updateLocalTransform() {
        glm::mat4 transform4x4 = glm::mat4(1.0f);
        transform4x4 = glm::translate(transform4x4, glm::vec3(m_Position, 0.0f));
        transform4x4 = glm::translate(transform4x4, glm::vec3(m_Pivot, 0.0f));
        transform4x4 = glm::rotate(transform4x4, m_Rotation, glm::vec3(0.0f, 0.0f, 1.0f));
        transform4x4 = glm::scale(transform4x4, glm::vec3(m_Scale, 1.0f));
        transform4x4 = glm::translate(transform4x4, glm::vec3(-m_Pivot, 0.0f));
        m_LocalTransform = glm::mat3(transform4x4);

        m_TransformDirty = false;
    }


    // ==================== 层级管理 ====================

    void ModelPart::addChild(std::unique_ptr<ModelPart> child) {
        if (!child || child.get() == this) {
            throw std::invalid_argument("Cannot add self or null as child");
        }
        if (child->m_Parent) {
            child->m_Parent->removeChild(child.get());
        }
        child->m_Parent = this;
        m_Children.push_back(std::move(child));
        m_Children.back()->markTransformDirty();
        m_Children.back()->recomputeWorldTransformRecursive();
    }

    std::unique_ptr<ModelPart> ModelPart::removeChild(ModelPart* child) {
        auto it = std::find_if(m_Children.begin(), m_Children.end(),
            [child](const auto& ptr) { return ptr.get() == child; });

        if (it != m_Children.end()) {
            std::unique_ptr<ModelPart> removedChild = std::move(*it);
            m_Children.erase(it);
            removedChild->m_Parent = nullptr;
            removedChild->markTransformDirty();
            removedChild->recomputeWorldTransformRecursive();
            return removedChild;
        }
        return nullptr;
    }

    const std::vector<std::unique_ptr<ModelPart>>& ModelPart::getChildren() const { return m_Children; }

    ModelPart* ModelPart::findChild(const std::string& name) {
        for (const auto& child : m_Children) {
            if (child->getName() == name) {
                return child.get();
            }
        }
        return nullptr;
    }

    ModelPart* ModelPart::findChildRecursive(const std::string& name) {
        if (auto found = findChild(name)) return found;
        for (const auto& child : m_Children) {
            if (auto found = child->findChildRecursive(name)) return found;
        }
        return nullptr;
    }

    // ==================== 变换系统 ====================

    void ModelPart::setPosition(const glm::vec2& pos) {
        m_Position = pos;
        markTransformDirty();
        recomputeWorldTransformRecursive();
    }

    void ModelPart::setRotation(float radians) {
        m_Rotation = radians;
        markTransformDirty();
        recomputeWorldTransformRecursive();
    }

    void ModelPart::setScale(const glm::vec2& scale) {
        m_Scale = scale;
        markTransformDirty();
        recomputeWorldTransformRecursive();
    }

    void ModelPart::setPivot(const glm::vec2& pivot) {
        if (m_Pivot != pivot) {
            m_Pivot = pivot;
            markTransformDirty();
        }
    }

    const glm::vec2& ModelPart::getPivot() const {
        return m_Pivot;
    }

    void ModelPart::translate(const glm::vec2& delta) { setPosition(m_Position + delta); }
    void ModelPart::rotate(float deltaRadians) { setRotation(m_Rotation + deltaRadians); }
    void ModelPart::scale(const glm::vec2& factor) { setScale(m_Scale * factor); }

    void ModelPart::recomputeWorldTransformRecursive() {
        if (m_TransformDirty) {
            updateLocalTransform();
        }
        if (m_Parent) {
            m_WorldTransform = m_Parent->m_WorldTransform * m_LocalTransform;
        }
        else {
            m_WorldTransform = m_LocalTransform;
        }

        // 重要：部件变换后，它拥有的所有网格的顶点也需要更新
        for (const auto& mesh : m_Meshes) {
            mesh->markDirty(); // 标记网格需要重新计算顶点和边界
        }

        for (auto& child : m_Children) {
            child->recomputeWorldTransformRecursive();
        }
    }

    void ModelPart::updateMeshVertices() {
        for (const auto& mesh : m_Meshes) {
            if (mesh) {
                mesh->markDirty();
                mesh->updateBounds();
            }
        }
    }

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

    void ModelPart::addMesh(std::unique_ptr<Mesh2D> mesh) {
        if (mesh) {
            mesh->setModelPart(this);
            m_Meshes.push_back(std::move(mesh));
            m_BoundsDirty = true;
        }
    }

    bool ModelPart::removeMesh(Mesh2D* mesh) {
        auto it = std::find_if(m_Meshes.begin(), m_Meshes.end(),
            [mesh](const auto& ptr) { return ptr.get() == mesh; });

        if (it != m_Meshes.end()) {
            m_Meshes.erase(it);
            m_BoundsDirty = true;
            return true;
        }
        return false;
    }

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

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

    glm::vec2 ModelPart::localToWorld(const glm::vec2& localPoint) const {
        return glm::vec2(m_WorldTransform * glm::vec3(localPoint, 1.0f));
    }

    glm::vec2 ModelPart::worldToLocal(const glm::vec2& worldPoint) const {
        return glm::vec2(glm::inverse(m_WorldTransform) * glm::vec3(worldPoint, 1.0f));
    }

    void ModelPart::updateBounds() const {
        for (const auto& mesh_ptr : m_Meshes) {
            if (mesh_ptr) {
                const util::BoundingBox& meshLocalBounds = mesh_ptr->getBounds();
                mesh_ptr->updateBounds();
            }
        }
        m_BoundsDirty = false;
    }

    util::BoundingBox ModelPart::getWorldBounds() {
        if (m_BoundsDirty) updateBounds();
        util::BoundingBox worldBounds;
        for (const auto& mesh : m_Meshes) {
            util::BoundingBox localBounds = mesh->getBounds();
            if (localBounds.isValid()) {
                for (const auto& corner : localBounds.getCorners()) {
                    worldBounds.expand(localToWorld(corner));
                }
            }
        }
        return worldBounds;
    }

    bool ModelPart::isEffectivelyVisible() const {
        if (!m_IsVisible) return false;
        if (m_Parent) return m_Parent->isEffectivelyVisible();
        return true;
    }

    // ==================== Getters & Setters ====================

    const std::string& ModelPart::getName() const { return m_Name; }
    void ModelPart::setName(const std::string& name) { m_Name = name; }
    ModelPart* ModelPart::getParent() const { return m_Parent; }
    const glm::vec2& ModelPart::getPosition() const { return m_Position; }
    float ModelPart::getRotation() const { return m_Rotation; }
    const glm::vec2& ModelPart::getScale() const { return m_Scale; }
    const glm::mat3& ModelPart::getLocalTransform() const { return m_LocalTransform; }
    const glm::mat3& ModelPart::getWorldTransform() const { return m_WorldTransform; }
    bool ModelPart::isVisible() const { return m_IsVisible; }
    void ModelPart::setVisible(bool visible) { m_IsVisible = visible; }
    ModelPart::BlendMode ModelPart::getBlendMode() const { return m_BlendMode; }
    void ModelPart::setBlendMode(BlendMode mode) { m_BlendMode = mode; }
    float ModelPart::getOpacity() const { return m_Opacity; }
    void ModelPart::setOpacity(float opacity) { m_Opacity = std::clamp(opacity, 0.0f, 1.0f); }

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

    AnimationParameter* ModelPart::createParameter(const std::string& id, float min, float max, float defaultValue) {
        auto it = m_Parameters.emplace(id, AnimationParameter(id, min, max, defaultValue));
        return &it.first->second;
    }

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

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

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

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

} // namespace Vivid2D