#pragma once

#ifndef PHYSICS_SYSTEM_H
#define PHYSICS_SYSTEM_H

#include <glm/glm.hpp>
#include <glm/gtx/norm.hpp>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <chrono>
#include <Object.h>


namespace Vivid2D {
    class Model2D;
    class ModelPart;
}

namespace Vivid2D::util {
    
    class PhysicsParticle;
    class PhysicsSpring;
    struct PhysicsConstraint;
    struct PhysicsCollider;
    class PositionConstraint;
    class DistanceConstraint;
    class CircleCollider;
    class RectangleCollider;

    /**
     * 物理性能报告
     */
    struct VIVID_2D_MYDLL_API PhysicsPerformanceReport {
        const size_t particleCount;
        const size_t springCount;
        const size_t constraintCount;
        const size_t colliderCount;
        const float averageUpdateTime;
        const int totalUpdates;

        PhysicsPerformanceReport(size_t pCount, size_t sCount, size_t cCount, size_t colCount, float avgTime, int updates);
        std::string toString() const;
    };

    /**
     * 2D物理系统，用于处理模型的物理模拟
     * 支持弹簧系统、碰撞检测、重力等物理效果
     */
    class VIVID_2D_MYDLL_API PhysicsSystem {
    public:
        // ==================== 构造器 ====================
        PhysicsSystem();

        // ==================== 初始化方法 ====================
        void initialize();
        void reset();

        // ==================== 粒子管理 ====================
        std::shared_ptr<PhysicsParticle> addParticle(const std::string& id, glm::vec2 position, float mass);
        std::shared_ptr<PhysicsParticle> addParticleFromModelPart(const std::string& id, std::shared_ptr<ModelPart> part, float mass);
        bool removeParticle(const std::string& id);
        std::shared_ptr<PhysicsParticle> getParticle(const std::string& id);

        // ==================== 弹簧管理 ====================
        std::shared_ptr<PhysicsSpring> addSpring(const std::string& id, std::shared_ptr<PhysicsParticle> a, std::shared_ptr<PhysicsParticle> b, float restLength, float stiffness, float damping);
        std::shared_ptr<PhysicsSpring> addSpring(const std::string& id, std::shared_ptr<PhysicsParticle> a, std::shared_ptr<PhysicsParticle> b, float stiffness, float damping);
        bool removeSpring(const std::shared_ptr<PhysicsSpring>& spring);

        // ==================== 约束管理 ====================
        std::shared_ptr<PositionConstraint> addPositionConstraint(std::shared_ptr<PhysicsParticle> particle, glm::vec2 targetPosition);
        std::shared_ptr<DistanceConstraint> addDistanceConstraint(std::shared_ptr<PhysicsParticle> particle, std::shared_ptr<PhysicsParticle> target, float maxDistance);
        bool removeConstraint(const std::shared_ptr<PhysicsConstraint>& constraint);

        // ==================== 碰撞管理 ====================
        std::shared_ptr<CircleCollider> addCircleCollider(const std::string& id, glm::vec2 center, float radius);
        std::shared_ptr<RectangleCollider> addRectangleCollider(const std::string& id, glm::vec2 center, float width, float height);
        bool removeCollider(const std::shared_ptr<PhysicsCollider>& collider);

        // ==================== 风力方法 ====================
        void setWindForce(float x, float y);
        void setWindForce(const glm::vec2& windForce);
        glm::vec2 getWindForce() const;
        void setWindEnabled(bool enabled);
        bool isWindEnabled() const;

        // ==================== 更新系统 ====================
        void update(float deltaTime, Model2D& model);

        // ==================== 性能统计 ====================
        PhysicsPerformanceReport getPerformanceReport() const;

        // ==================== Getter/Setter ====================
        glm::vec2 getGravity() const;
        void setGravity(float x, float y);
        void setGravity(const glm::vec2& gravity);

        float getAirResistance() const;
        void setAirResistance(float airResistance);

        float getTimeScale() const;
        void setTimeScale(float timeScale);

        bool isEnabled() const;
        void setEnabled(bool enabled);

        bool isInitialized() const;

        const std::unordered_map<std::string, std::shared_ptr<PhysicsParticle>>& getParticles() const;
        const std::vector<std::shared_ptr<PhysicsSpring>>& getSprings() const;
        const std::vector<std::shared_ptr<PhysicsConstraint>>& getConstraints() const;
        const std::vector<std::shared_ptr<PhysicsCollider>>& getColliders() const;

        bool hasActivePhysics();

    private:
        // ==================== 物理参数 ====================
        glm::vec2 m_gravity;
        float m_airResistance;
        float m_timeScale;
        bool m_enabled;

        // ==================== 物理组件 ====================
        std::unordered_map<std::string, std::shared_ptr<PhysicsParticle>> m_particles;
        std::vector<std::shared_ptr<PhysicsSpring>> m_springs;
        std::vector<std::shared_ptr<PhysicsConstraint>> m_constraints;
        std::vector<std::shared_ptr<PhysicsCollider>> m_colliders;

        // ==================== 状态管理 ====================
        bool m_initialized;
        std::chrono::steady_clock::time_point m_lastUpdateTime;
        float m_accumulatedTime;
        const int m_maxSubSteps;
        const float m_fixedTimeStep;

        // ==================== 性能统计 ====================
        int m_updateCount;
        float m_averageUpdateTime;

        // ==================== 风力参数 ====================
        glm::vec2 m_windForce;
        bool m_windEnabled;

        // ==================== 更新流程 ====================
        void updatePhysics(float deltaTime);
        void syncVelocitiesFromPositions(float deltaTime);
        void applyGravity();
        void applyWind();
        void applyAirResistance(float deltaTime);
        void handleParticleCollisions(float deltaTime);
        void applyToModel(Model2D& model);
        void updatePerformanceStats(long long nanoTime);
    };


    // =================================================================================
    //                                  内部类定义
    // =================================================================================

    /**
     * 物理粒子类
     */
    class VIVID_2D_MYDLL_API PhysicsParticle {
    public:
        PhysicsParticle(std::string id, glm::vec2 position, float mass);

        void update(float deltaTime);
        void addForce(const glm::vec2& force);
        void clearForces();

        void translatePosition(const glm::vec2& delta);
        void setPreviousPosition(const glm::vec2& prev);
        void applyNewVelocity(const glm::vec2& newVelocity);

        // Getters
        const std::string& getId() const { return m_id; }
        glm::vec2 getPosition() const { return m_position; }
        glm::vec2 getPreviousPosition() const { return m_previousPosition; }
        glm::vec2 getVelocity() const { return m_velocity; }
        glm::vec2 getAcceleration() const { return m_acceleration; }
        float getMass() const { return m_mass; }
        float getInverseMass() const { return m_inverseMass; }
        float getRadius() const { return m_radius; }
        bool isMovable() const { return m_movable; }
        bool isAffectedByGravity() const { return m_affectedByGravity; }
        bool isAffectedByWind() const { return m_affectedByWind; }
        void* getUserData() const { return m_userData; }

        // Setters
        void setPosition(const glm::vec2& position) { m_position = position; }
        void setVelocity(const glm::vec2& velocity) { m_velocity = velocity; }
        void setRadius(float radius) { m_radius = radius; }
        void setMovable(bool movable) { m_movable = movable; }
        void setAffectedByGravity(bool affected) { m_affectedByGravity = affected; }
        void setAffectedByWind(bool affected) { m_affectedByWind = affected; }
        void setUserData(void* data) { m_userData = data; }

    private:
        friend class PhysicsSystem;
        std::string m_id;
        glm::vec2 m_position;
        glm::vec2 m_previousPosition;
        glm::vec2 m_velocity;
        glm::vec2 m_acceleration;
        glm::vec2 m_forceAccumulator;
        float m_mass;
        float m_inverseMass;
        float m_radius;
        bool m_movable;
        bool m_affectedByGravity;
        bool m_affectedByWind;
        void* m_userData = nullptr;
    };

    /**
     * 物理弹簧类
     */
    class VIVID_2D_MYDLL_API PhysicsSpring {
    public:
        PhysicsSpring(std::string id, std::shared_ptr<PhysicsParticle> a, std::shared_ptr<PhysicsParticle> b, float restLength, float stiffness, float damping);
        void applyForce(float deltaTime);

        // Getters & Setters
        const std::string& getId() const { return m_id; }
        std::shared_ptr<PhysicsParticle> getParticleA() const { return m_particleA; }
        std::shared_ptr<PhysicsParticle> getParticleB() const { return m_particleB; }
        float getRestLength() const { return m_restLength; }
        float getStiffness() const { return m_stiffness; }
        float getDamping() const { return m_damping; }
        bool isEnabled() const { return m_enabled; }
        void setEnabled(bool enabled) { m_enabled = enabled; }

    private:
        std::string m_id;
        std::shared_ptr<PhysicsParticle> m_particleA;
        std::shared_ptr<PhysicsParticle> m_particleB;
        float m_restLength;
        float m_stiffness;
        float m_damping;
        bool m_enabled;
    };

    /**
     * 物理约束接口
     */
    struct VIVID_2D_MYDLL_API PhysicsConstraint {
        virtual ~PhysicsConstraint() = default;
        virtual void apply(float deltaTime) = 0;
        virtual std::shared_ptr<PhysicsParticle> getParticle() const = 0;
        virtual bool isEnabled() const = 0;
        virtual void setEnabled(bool enabled) = 0;
    };

    /**
     * 位置约束
     */
    class VIVID_2D_MYDLL_API PositionConstraint : public PhysicsConstraint {
    public:
        PositionConstraint(std::shared_ptr<PhysicsParticle> particle, glm::vec2 targetPosition);
        void apply(float deltaTime) override;

        std::shared_ptr<PhysicsParticle> getParticle() const override { return m_particle; }
        bool isEnabled() const override { return m_enabled; }
        void setEnabled(bool enabled) override { m_enabled = enabled; }

        glm::vec2 getTargetPosition() const { return m_targetPosition; }
        void setTargetPosition(const glm::vec2& target) { m_targetPosition = target; }
        float getStrength() const { return m_strength; }
        void setStrength(float strength) { m_strength = glm::clamp(strength, 0.0f, 1.0f); }

    private:
        std::shared_ptr<PhysicsParticle> m_particle;
        glm::vec2 m_targetPosition;
        float m_strength;
        bool m_enabled;
    };

    /**
     * 距离约束
     */
    class VIVID_2D_MYDLL_API DistanceConstraint : public PhysicsConstraint {
    public:
        DistanceConstraint(std::shared_ptr<PhysicsParticle> particle, std::shared_ptr<PhysicsParticle> target, float maxDistance);
        void apply(float deltaTime) override;

        std::shared_ptr<PhysicsParticle> getParticle() const override { return m_particle; }
        bool isEnabled() const override { return m_enabled; }
        void setEnabled(bool enabled) override { m_enabled = enabled; }

        std::shared_ptr<PhysicsParticle> getTarget() const { return m_target; }
        float getMaxDistance() const { return m_maxDistance; }

    private:
        std::shared_ptr<PhysicsParticle> m_particle;
        std::shared_ptr<PhysicsParticle> m_target;
        float m_maxDistance;
        bool m_enabled;
    };

    /**
     * 物理碰撞体接口
     */
    struct VIVID_2D_MYDLL_API PhysicsCollider : public Object {
        virtual ~PhysicsCollider() = default;
        virtual bool collidesWith(const PhysicsParticle& particle) const = 0;
        virtual void resolveCollision(PhysicsParticle& particle, float deltaTime) = 0;
        virtual const std::string& getId() const = 0;
        virtual bool isEnabled() const = 0;
        virtual void setEnabled(bool enabled) = 0;
    };

    /**
     * 圆形碰撞体
     */
    class VIVID_2D_MYDLL_API CircleCollider : public PhysicsCollider {
    public:
        std::string getClassName() const override { return "CircleCollider"; }
        CircleCollider(std::string id, glm::vec2 center, float radius);
        bool collidesWith(const PhysicsParticle& particle) const override;
        void resolveCollision(PhysicsParticle& particle, float deltaTime) override;

        const std::string& getId() const override { return m_id; }
        bool isEnabled() const override { return m_enabled; }
        void setEnabled(bool enabled) override { m_enabled = enabled; }

        glm::vec2 getCenter() const { return m_center; }
        void setCenter(const glm::vec2& center) { m_center = center; }
        float getRadius() const { return m_radius; }

    private:
        std::string m_id;
        glm::vec2 m_center;
        float m_radius;
        bool m_enabled;
    };

    /**
     * 矩形碰撞体
     */
    class VIVID_2D_MYDLL_API RectangleCollider : public PhysicsCollider {
    public:
        std::string getClassName() const override { return "RectangleCollider"; }
        RectangleCollider(std::string id, glm::vec2 center, float width, float height);
        bool collidesWith(const PhysicsParticle& particle) const override;
        void resolveCollision(PhysicsParticle& particle, float deltaTime) override;

        const std::string& getId() const override { return m_id; }
        bool isEnabled() const override { return m_enabled; }
        void setEnabled(bool enabled) override { m_enabled = enabled; }

        glm::vec2 getCenter() const { return m_center; }
        void setCenter(const glm::vec2& center) { m_center = center; }
        float getWidth() const { return m_width; }
        float getHeight() const { return m_height; }

    private:
        std::string m_id;
        glm::vec2 m_center;
        float m_width;
        float m_height;
        bool m_enabled;
    };

} // namespace Vivid2D::util

#endif // PHYSICS_SYSTEM_H
