#pragma once
#include "../component.h"

namespace ecs {

    /**
     * Enum for different shader types used in rendering.
     * This enum is used to specify the type of shader to be applied to a model.
     */
enum class ShaderType
{
    CEL_SHADING,
    LIGHTING,
    NORMAL_MAPPING,
    SPECULAR_MAPPING,
    REFLECTION,
    REFRACTION,
    TEXTURE,
    SKYBOX,
    SUNLIGHT,
    ALPHA_MAPPING
};

class ShaderComponent : public Component {
public:

    /**
     * Builder for the ShaderComponent class.
     * Initializes the active shader to LIGHTING by default.
     */
    ShaderComponent() : m_activeShader(ShaderType::LIGHTING) {}
    ~ShaderComponent() = default;

    void Initialize() override {}
    void Update(float deltaTime) override {}

    /**
     * Get the currently active shader type.
     * @return The active shader type as a ShaderType enum.
     */
    ShaderType GetActiveShader() const { return m_activeShader; }
    /**
     * Set the active shader type.
     * This method allows changing the shader type used for rendering.
     * @param shader The shader type to set as a ShaderType enum.
     */
    void SetActiveShader(ShaderType shader) { m_activeShader = shader; }

    /**
     * Set the active shader type from a string.
     * This method converts a string representation of a shader type to the corresponding ShaderType enum.
     * @param shaderName The name of the shader type as a string.
     * @return The ShaderType enum corresponding to the provided string.
     */
    static ShaderType StringToShaderType(const std::string& str) {
        if (str == "ALPHA_MAPPING") return ShaderType::ALPHA_MAPPING;
        if (str == "CEL_SHADING") return ShaderType::CEL_SHADING;
        if (str == "NORMAL_MAPPING") return ShaderType::NORMAL_MAPPING;
        if (str == "SPECULAR_MAPPING") return ShaderType::SPECULAR_MAPPING;
        if (str == "TEXTURE") return ShaderType::TEXTURE;
        if (str == "LIGHTING") return ShaderType::LIGHTING;
        if (str == "SUNLIGHT") return ShaderType::SUNLIGHT;
        if (str == "SKYBOX") return ShaderType::SKYBOX;
        if (str == "REFLECTION") return ShaderType::REFLECTION;
        if (str == "REFRACTION") return ShaderType::REFRACTION;
        return ShaderType::TEXTURE;
    }

    /**
     * Convert a ShaderType enum to its string representation.
     * This method provides a string name for each shader type.
     * @param type The shader type as a ShaderType enum.
     * @return The name of the shader type as a string.
     */
    static std::string ShaderTypeToString(ShaderType type) {
        switch (type) {
            case ShaderType::ALPHA_MAPPING: return "ALPHA_MAPPING";
            case ShaderType::CEL_SHADING: return "CEL_SHADING";
            case ShaderType::NORMAL_MAPPING: return "NORMAL_MAPPING";
            case ShaderType::SPECULAR_MAPPING: return "SPECULAR_MAPPING";
            case ShaderType::TEXTURE: return "TEXTURE";
            case ShaderType::LIGHTING: return "LIGHTING";
            case ShaderType::SUNLIGHT: return "SUNLIGHT";
            case ShaderType::SKYBOX: return "SKYBOX";
            case ShaderType::REFLECTION: return "REFLECTION";
            case ShaderType::REFRACTION: return "REFRACTION";
            default: return "TEXTURE";
        }
    }

    std::string Serialize() const override
    {
        std::stringstream ss;
        ss  << "ShaderComponent:"
            << ShaderTypeToString(GetActiveShader());
        return ss.str();
    }

    bool Deserialize(const std::string& data) override {
        std::stringstream ss(data);
        std::string type;
        std::getline(ss, type, ':');
    
        if (type != "ShaderComponent") return false;
    
        std::string shaderTypeStr;
        std::getline(ss, shaderTypeStr);
    
        SetActiveShader(StringToShaderType(shaderTypeStr));
        return true;
    }

    void OnImGuiRender() override {
        ShaderType currentShader = GetActiveShader();
        int shaderIndex = static_cast<int>(currentShader);
        const char* shaderNames[] = {
            "CEL_SHADING",
            "LIGHTING",
            "NORMAL_MAPPING",
            "SPECULAR_MAPPING",
            "REFLECTION",
            "REFRACTION",
            "TEXTURE",
            "SKYBOX",
            "SUNLIGHT",
            "ALPHA_MAPPING"
        };
        
        if (ImGui::Combo("Active Shader", &shaderIndex, shaderNames, IM_ARRAYSIZE(shaderNames))) {
            SetActiveShader(static_cast<ShaderType>(shaderIndex));
        }
    }

private:
    ShaderType m_activeShader;
};

}  // namespace ecs
