#pragma once
#include <sstream>

#include "../component.h"
#include <string>

namespace ecs {
    /**
     * Enum for different types of objects in the ECS.
     * The object types is used to specify the collision type of the object.
     */
    enum class ObjectType
    {
        Sphere,
        Cube,
        Terrain,
        Unknown
    };

class IdentityComponent : public Component {
public:
    /**
     * Builder for the IdentityComponent class.
     */
    IdentityComponent() : m_id(0), m_type(ObjectType::Unknown) {}
    explicit IdentityComponent(int id) : m_id(id), m_type(ObjectType::Unknown) {}
    IdentityComponent(int id, const std::string& name) : m_id(id), m_name(name), m_type(ObjectType::Unknown) {}
    ~IdentityComponent() = default;

    /**
     * Initialize the component.
     * This method is called when the component is added to an entity.
     * It can be used to set up initial values or perform any necessary setup.
     */
    void Initialize() override {}
    //void Update(float deltaTime) override {}
    
    /**
     * Get the ID stored by the component.
     * @return The ID as an int.
     */
    int GetId() const { return m_id; }
    /**
     * Set the ID for the component.
     * @param id The ID to set.
     */
    void SetId(int id) { m_id = id; }

    /**
     * Get the name of the object.
     * @return The name as a string.
     */
    const std::string& GetName() const { return m_name; }
    /**
     * Set the name of the object.
     * @param name The name to set.
     */
    void SetName(const std::string& name) { m_name = name; }

    /**
     * Get the type of the object.
     * @return The type as an ObjectType enum.
     */
    ObjectType GetType() const { return m_type; }
    /**
     * Set the type of the object.
     * @param type The type to set as an ObjectType enum.
     */
    void SetType(ObjectType type) { m_type = type; }

    /**
     * Convert an ObjectType to a string representation.
     * @param type The ObjectType to convert.
     * @return A string representation of the ObjectType.
     */
    static std::string ObjectTypeToString(ObjectType type) {
        switch (type) {
            case ObjectType::Cube: return "Cube";
            case ObjectType::Sphere: return "Sphere";
            case ObjectType::Terrain: return "Terrain";
            default: return "Unknown";
        }
    }

    /**
     * Convert a string representation to an ObjectType.
     * @param str The string to convert.
     * @return The corresponding ObjectType, or Unknown if the string does not match any type.
     */
    static ObjectType StringToObjectType(const std::string& str) {
        if (str == "Cube") return ObjectType::Cube;
        if (str == "Sphere") return ObjectType::Sphere;
        if (str == "Terrain") return ObjectType::Terrain;
        return ObjectType::Unknown;
    }

    /**
     * Serialize the component to a string.
     * Format: "IdentityComponent:id:name:type"
     * @return A string representation of the component.
     */
    std::string Serialize() const override {
        std::stringstream ss;
        ss << "IdentityComponent:"
           << GetId() << ":"
           << GetName() << ":"
           << ObjectTypeToString(GetType());
        return ss.str();
    }

    /**
     * Deserialize the component from a string.
     * Expected format: "id:name:type"
     * @param data The string data to deserialize from.
     * @return True if deserialization was successful, otherwise false.
     */
    bool Deserialize(const std::string& data) override {
        std::stringstream ss(data);
        std::string type;
        std::getline(ss, type, ':');
    
        if (type != "IdentityComponent") return false;
    
        std::string token, name, objectTypeStr;
        int id;
    
        std::getline(ss, token, ':'); id = std::stoi(token);
        std::getline(ss, name, ':');
        std::getline(ss, objectTypeStr);
    
        SetId(id);
        SetName(name);
        SetType(StringToObjectType(objectTypeStr));
        return true;
    }

    void OnImGuiRender() override {
        ImGui::Text("ID: %d", m_id);
        char nameBuffer[256];
        strncpy_s(nameBuffer, m_name.c_str(), sizeof(nameBuffer));
        if (ImGui::InputText("#Name", nameBuffer, sizeof(nameBuffer))) {
            m_name = std::string(nameBuffer);
        }

        const char* objectTypes[] = { "Unknown", "Cube", "Sphere", "Terrain" };
        int currentTypeIndex = static_cast<int>(m_type);
        if (ImGui::Combo("Object Type", &currentTypeIndex, objectTypes, IM_ARRAYSIZE(objectTypes))) {
            m_type = static_cast<ObjectType>(currentTypeIndex);
        }
    }

private:
    int m_id; // ID unique de l'objet
    std::string m_name; // Nom de l'objet
    ObjectType m_type; // Type de l'objet (Cube, Sphere, Terrain, etc.)
};

}  // namespace ecs
