#include "ElementDrawer.hpp"
#include "BehaviourScriptRegistry.hpp"
#include "elements/ShaderRegistry.hpp"
#include "BehaviourScripts/Camera.hpp"
#include "windows/HirearchieView.hpp"
#include <algorithm>

namespace TSE::EDITOR
{
    #pragma region helper
    bool InputText(const char* label, std::string& str, size_t bufferSize = 256) {
        std::vector<char> buffer(bufferSize);
        strncpy(buffer.data(), str.c_str(), bufferSize);
        buffer[bufferSize - 1] = '\0';

        bool changed = ImGui::InputText(label, buffer.data(), bufferSize);
        if (changed) {
            str = std::string(buffer.data());
        }
        return changed;
    }
    void BeginList(std::string listName)
    {
        ImGui::BeginChild(listName.c_str(), {0,150}, ImGuiChildFlags_Borders);
    }
    bool ListAddBtn(std::string label = "Add")
    {
        float available_width = ImGui::GetContentRegionAvail().x;
        return ImGui::Button(label.c_str(),{available_width, 0});
    }
    void BeginListItem(std::string name, float customHeight = 20)
    {
        float available_width = ImGui::GetContentRegionAvail().x;
        ImGui::BeginChild(name.c_str(),{available_width - 30, customHeight});
    }
    void EndListItem()
    {
        ImGui::EndChild();
    }
    bool ListItemXBotton(std::string id)
    {
        ImGui::SameLine();
        return ImGui::Button(id.c_str(), {20,0});
    }
    void EndList()
    {
        ImGui::EndChild();
    }
    #pragma endregion

    void ElementDrawer::DrawAddDropdown(const std::vector<string>& options, string& selectedOption)
    {
        ImGuiStyle& style = ImGui::GetStyle();
        float availableWidth = ImGui::GetContentRegionAvail().x;

        // Add Button
        if (ImGui::Button("Add", ImVec2(availableWidth, 0))) {
            addDropdownOpen = !addDropdownOpen;
        }

        if (addDropdownOpen)
        {
            // Begin Popup
            ImGui::BeginChild("##AddDropdownChild", ImVec2(availableWidth, 300), true);

            // Suchfeld mit X Button
            ImGui::PushItemWidth(-style.FramePadding.x * 4 - 24); // Platz für Clear Button
            ImGui::InputTextWithHint("##SearchField", "Search", searchBuffer, IM_ARRAYSIZE(searchBuffer));
            ImGui::PopItemWidth();

            ImGui::SameLine();
            if (ImGui::Button("X")) {
                searchBuffer[0] = '\0';
            }

            ImGui::Separator();

            // Scrollbare Liste mit Filter
            ImGui::BeginChild("##OptionsList", ImVec2(0, 250), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);

            int count = 0;
            for (const auto& option : options)
            {
                if (strlen(searchBuffer) == 0 || option.find(searchBuffer) != std::string::npos)
                {
                    if (ImGui::Selectable(option.c_str()))
                    {
                        selectedOption = option;
                        addDropdownOpen = false;
                        break;
                    }
                    count++;
                    if (count >= 50) break; // Begrenze maximal gezeichnete Elemente zur Performance
                }
            }

            ImGui::EndChild();
            ImGui::EndChild();
        }
    }
    void ElementDrawer::Draw(Transformable* element,const bool& debug) {
        ImGui::SeparatorText("Transform");
        ImGui::Checkbox("##checkbox", &element->_enabled);
        ImGui::SameLine();
        InputText("<-- Name##", element->name);
        ImGui::DragFloat3("<-- Position", &element->position.x, 0.1f);
        ImGui::DragFloat3("<--Scale", &element->scale.x, 0.1f);
        Vector3 euler = element->GetEuler();
        ImGui::DragFloat3("<-- Rotation", &(euler.x), 0.1f);
        element->SetEuler(euler);
        ImGui::Spacing();
        if(debug)
        {
            
            ImGui::BeginDisabled();
            ImGui::Text(("ID: " + to_string(element->id)).c_str());
            ImGui::Text(("Child Count: " + std::to_string(element->GetChildren().size())).c_str());
            ImGui::Text(("Component Count: " + std::to_string(element->GetComponentCount())).c_str());
            ImGui::EndDisabled();
            ImGui::Spacing();
        }
        if(element->GetComponentCount() > 0)
            ImGui::SeparatorText("Components");
        for (int i = 0; i < element->GetComponentCount(); i++)
        {
            Draw(element->GetBehaviourScriptAt(i), debug, i);
        }
        ImGui::Spacing();
        ImGui::Separator();
        ImGui::Spacing();

        std::vector<std::string> behaviourScripts;
        for (const auto& [name, _] : BehaviourScriptRegistry::GetRegistry())
        {
            behaviourScripts.push_back(name);
        }

        std::string selectedScript = "";

        DrawAddDropdown(behaviourScripts, selectedScript);
        
        if (!selectedScript.empty())
        {
            // Erzeuge das Script:
            BehaviourScript* script = BehaviourScriptRegistry::CreateBehaviourScript(selectedScript);
            if (script)
            {
                if(element->HasBehaviourScript(typeid(*script).name()))
                {
                    delete script;
                }
                else
                    element->AddBehaviourScript(script);
            }
            selectedScript = ""; // Reset nach Hinzufügen
        }

    }
    void ElementDrawer::Draw(Scene* element,const bool& debug) {
        ImGui::Text("Scene Name: %s", element->GetName().c_str());
        ImGui::Text("Layer Count: %d", element->GetLayerCount());
    }
    void ElementDrawer::Draw(Layer* element,const bool& debug) {
        ImGui::Text("Layer Name: %s", element->GetName().c_str());
    }
    void ElementDrawer::Draw(BehaviourScript *element, const bool &debug, const int& id)
    {
        ImGui::PushID(("Script##" + std::to_string(id)).c_str());
        std::string name = element->GetName();
        if(ImGui::CollapsingHeader(name.c_str()))
        {
            bool enabled = element->IsEnabled();
            ImGui::Checkbox("enabled", &enabled);
            element->SetEnabled(enabled);
            if(name == "Renderable")
            {
                Draw((Renderable*)element, debug);
            }
            else if (name == "Mesh Container")
            {
                Draw((MeshContainer*)element, debug);
            }
            else if (name == "Image")
            {
                Draw((Image*)element, debug);
            }
            else if (name == "Image Animation")
            {
                Draw((ImageAnimation*)element, debug);
            }
            else if (name == "Rect Base")
            {
                Draw((RectBase*)element, debug);
            }
            else if (name == "Audio Source")
            {
                Draw((AudioSource*)element, debug);
            }
            else if (name == "Camera")
            {
                Draw((Camera*)element, debug);
            }
            else if (name == "Particle System")
            {
                Draw((ParticleSystem*)element, debug);
            }
            else if (name == "Tile Map")
            {
                Draw((TileMap*)element, debug);
            }
            else
            {
                element->CustomDraw(debug);
            }
        }
        ImGui::PopID();
    }
    void ElementDrawer::Draw(Renderable *element, const bool &debug)
    {
        ImGui::SeparatorText("Material");
        int height = 100;
        if(element->GetMaterial() == nullptr)
        {
            height = 35;
        }
        ImVec2 size(0, height);
        ImGui::BeginChild("MaterialViewer", size, ImGuiChildFlags_Borders);
        Draw(element->GetMaterial(), debug);
        ImGui::EndChild();
    }
    void ElementDrawer::Draw(MeshContainer *element, const bool &debug)
    {
        int height = ImGui::GetContentRegionAvail().x;
        if(element->GetMesh() == nullptr)
        {
            height = 35;
        }
        ImVec2 size(0, height);
        Draw(element->GetMesh(), debug, "Mesh", true);
    }
    void ElementDrawer::Draw(Image *element, const bool &debug)
    {
        int height = ImGui::GetContentRegionAvail().x + 50;
        if(element->GetSpritePtr() == nullptr)
        {
            height = 35;
        }
        ImVec2 size(0, height);
        ImGui::SeparatorText("Sprite");
        Draw(element->GetSpritePtr(), debug, "Sprite", true);
    }
    void ElementDrawer::Draw(ImageAnimation *element, const bool &debug)
    {
        int currentSelection = -1;
        int itemCount = element->GetImageAnimationSetCount();
        std::vector<std::string> items;
        for (int i = 0; i < itemCount; i++)
        {
            if(element->GetImageAnimationAt(i) == nullptr) continue;
            items.push_back(element->GetImageAnimationAt(i)->Name);
            if(element->GetImageAnimationAt(i)->Name == element->GetCurrentAnimation())
            {
                currentSelection = i;
            }
        }
        auto getter = [](void* vec, int idx, const char** out_text) {
            auto& vector = *static_cast<std::vector<std::string>*>(vec);
            if (idx < 0 || idx >= static_cast<int>(vector.size())) return false;
            *out_text = vector.at(idx).c_str();
            return true;
        };
        if(ImGui::Combo("Active animation", &currentSelection, getter, static_cast<void*>(&items), items.size()))
        {
            element->StartAnimation(items[currentSelection]);
        }
        items.clear();
        for (int i = 0; i < itemCount; i++)
        {
            if(element->GetImageAnimationAt(i) == nullptr)
            {
                items.push_back("NULL");
                continue;
            }
            items.push_back(element->GetImageAnimationAt(i)->Name);
        }
        ImGui::Text(("Frame: " + std::to_string(element->GetCurrentFrame())).c_str());
        if(debug)
        {
            ImGui::TextDisabled(("DeltaTime: " + std::to_string(element->GetDeltaTime())).c_str());
        }
        ImGui::SeparatorText("Animation Sets");
        BeginList("ImageAnimationSetList");
        if(ListAddBtn() && (itemCount == 0 || items[itemCount - 1] != "NULL"))
        {
            element->SetAnimationSet("NULL", nullptr);
            itemCount++;
            items.push_back("NULL");
        }
        for (int i = 0; i < itemCount; i++)
        {
            BeginListItem("subcomponent##" + std::to_string(i));
            Draw(element->GetImageAnimationAt(i),debug, items[i], true);
            EndListItem();
            if(ListItemXBotton("x##" + std::to_string(i)))
            {
                element->RemoveAnimationSet(items[i]);
                itemCount--;
                i--;
            }
        }
        EndList();
    }
    void ElementDrawer::Draw(RectBase *element, const bool &debug)
    {
        ImGui::DragFloat2("Size", &element->size.x);
        ImGui::Separator();

        if (ImGui::TreeNode("Anchors"))
        {
            ImGui::Text("Min");
            ImGui::DragFloat("X##anchor_min_x", &element->anchors.p1.x,0.2f);
            ImGui::DragFloat("Y##anchor_min_y", &element->anchors.p1.y,0.2f);

            ImGui::Text("Max");
            ImGui::DragFloat("X##anchor_max_x", &element->anchors.p2.x,0.2f);
            ImGui::DragFloat("Y##anchor_max_y", &element->anchors.p2.y,0.2f);

            ImGui::TreePop();
        }

        ImGui::Text("Pivot");
        ImGui::DragFloat("X##pivot_x", &element->pivit.x,0.2f);
        ImGui::DragFloat("Y##pivot_y", &element->pivit.y,0.2f);

    }
    void ElementDrawer::Draw(Material *element, const bool &debug)
    {
        if(element == nullptr)
        {
            ImGui::TextDisabled("No material");
            return;
        }
        else
        {
            InputText("Name", element->GetName());

            int currentSelection = -1;
            int itemCount = ShaderRegistry::GetShaderCount();
            std::vector<std::string> items;
            for (int i = 0; i < itemCount; i++)
            {
                if(ShaderRegistry::GetShaderAt(i) == nullptr) continue;
                items.push_back(ShaderRegistry::GetNameAt(i));
                if(ShaderRegistry::GetShaderAt(i) == element->GetShader())
                {
                    currentSelection = i;
                }
            }
            auto getter = [](void* vec, int idx, const char** out_text) {
                auto& vector = *static_cast<std::vector<std::string>*>(vec);
                if (idx < 0 || idx >= static_cast<int>(vector.size())) return false;
                *out_text = vector.at(idx).c_str();
                return true;
            };
            if(ImGui::Combo("Shader", &currentSelection, getter, static_cast<void*>(&items), items.size()))
            {
                element->SetShader(ShaderRegistry::GetShader(items[currentSelection]));
            }
            if(debug)
                ImGui::TextDisabled(to_string(element->GetID()).c_str());
            ImGui::Separator();
            int count = element->GetValueCount();
            for(int i = 0; i < count; i++)
            {
                std::tuple<std::any, std::string, std::string> tupel = element->GetValueAt(i);
                auto[ptr, type, name] = tupel;
                if (type == typeid(int).name())
                {
                    int value = element->GetValue<int>(name);
                    if(ImGui::InputInt(name.c_str(), &value))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(float).name())
                {
                    float value = element->GetValue<float>(name);
                    if(ImGui::InputFloat(name.c_str(), &value))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(Vector2).name())
                {
                    Vector2 value = element->GetValue<Vector2>(name);
                    if(ImGui::InputFloat2(name.c_str(), &value.x))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(Vector3).name())
                {
                    Vector3 value = element->GetValue<Vector3>(name);
                    if(ImGui::InputFloat3(name.c_str(), &value.x))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(Vector4).name())
                {
                    Vector4 value = element->GetValue<Vector4>(name);
                    if(ImGui::InputFloat4(name.c_str(), &value.x))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(Matrix4x4).name())
                {
                    Matrix4x4 value = element->GetValue<Matrix4x4>(name);
                    //TODO: need to implement;
                }
                else if (type == typeid(Color).name())
                {
                    Color value = element->GetValue<Color>(name);
                    if(ImGui::ColorEdit4(name.c_str(), &value.r))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(std::string).name())
                {
                    Vector4 value = element->GetValue<Vector4>(name);
                    if(ImGui::InputFloat4(name.c_str(), &value.x))
                    {
                        element->SetValue(name, value);
                    }
                }
                else if (type == typeid(Texture*).name())
                {
                    Texture* value = element->GetValue<Texture*>(name);
                    Draw(value, debug, name , true);
                }
                if (type == typeid(uint).name())
                {
                    int value = element->GetValue<uint>(name);
                    if(ImGui::InputInt(name.c_str(), &value))
                    {
                        element->SetValue(name, value);
                    }
                }
                else
                {
                    ImGui::TextDisabled(("Not Implemented: " + type).c_str());
                }
            }
        }
    }
    void ElementDrawer::Draw(Texture *element, const bool &debug, const std::string& label, const bool small)
    {
        if(element == nullptr)
        {
            ImGui::Text("No Texture Set");
            return;
        }
        if(small) DrawTextureCompact(element, debug, label);
        else DrawTextureNormal(element, debug, label);
    }
    void ElementDrawer::Draw(Sprite *element, const bool &debug, const std::string &label, const bool small)
    {
        if(element == nullptr)
        {
            ImGui::Text("No Sprite Set");
            return;
        }
        if(small) DrawSpriteCompact(element, debug, label);
        else DrawSpriteNormal(element, debug, label);
    }
    void ElementDrawer::Draw(Mesh *element, const bool &debug, const std::string &label, const bool small)
    {
        if(element == nullptr)
        {
            ImGui::Text("No Mesh Set");
            return;
        }
        if(small) DrawMeshCompact(element, debug, label);
        else DrawMeshNormal(element, debug, label);
    }
    void ElementDrawer::Draw(ImageAnimationSet *element, const bool &debug, const std::string &label, const bool small)
    {
        if(element == nullptr)
        {
            ImGui::Text("No Animation Set Asigned");
            return;
        }
        if(small) DrawImageAnimationSetCompact(element, debug, label);
        else DrawImageAnimationSetNormal(element, debug, label);
    }
    void ElementDrawer::Draw(AudioSource *element, const bool &debug)
    {
        float availWidth = ImGui::GetContentRegionAvail().x;
        int buttonCount = 3;
        float spacing = ImGui::GetStyle().ItemSpacing.x;
        float buttonWidth = (availWidth - (buttonCount - 1) * spacing) / buttonCount;
        float buttonHeight = 0.0f; // 0.0 = default height

        if (ImGui::Button("Play", ImVec2(buttonWidth, buttonHeight)))
        {
            element->StartClip(element->currentlyPlaying, false);
        }
        ImGui::SameLine();
        if (ImGui::Button("Pause", ImVec2(buttonWidth, buttonHeight)))
        {
            element->PausePlaying();
        }
        ImGui::SameLine();
        if (ImGui::Button("Stop", ImVec2(buttonWidth, buttonHeight)))
        {
            element->StopPlaying();
        }
        ImGui::Separator();
        bool global = element->GetGlobal();
        if(ImGui::Checkbox("Global", &global))
        {
            element->SetGlobal(global);
        }
        float minDistance = element->GetMinDistance();
        if(ImGui::DragFloat("Cutoff Distance", &minDistance))
        {
            element->SetMinDistance(minDistance);
        }
        float maxDistance = element->GetMaxDistance();
        if(ImGui::DragFloat("Falloff Distance", &maxDistance))
        {
            element->SetMaxDistance(maxDistance);
        }
        
        BeginList("Audio Clips");
        //if(ListAddBtn()) { }     // --> no add function for now maybe when asset manager is done
        for(int i = 0; i < element->clips.size(); i++)
        {
            BeginListItem("subcomponent##" + std::to_string(i));
            Draw(element->GetClipAt(i), debug, "", true);
            if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows))
            {
                // Check auf Doppelclick mit linker Maustaste
                if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
                {
                    element->StopPlaying();
                    element->currentlyPlaying = element->GetClipAt(i)->name;
                }
            }
            EndListItem();
            if(ListItemXBotton("x##" + std::to_string(i)))
            {
                element->RemoveClip(element->GetClipAt(i)->name);
            }
        }
        EndList();
    }
    void ElementDrawer::Draw(AudioClip *element, const bool &debug, const std::string &label, const bool small)
    {
        if(element == nullptr)
        {
            ImGui::Text("No Audio Clip Asigned");
            return;
        }
        if(small) DrawAudioClipCompact(element, debug, label);
        else DrawAudioClipNormal(element, debug, label);
    }
    void ElementDrawer::Draw(Camera *element, const bool &debug)
    {
        const bool isMain = (Camera::mainCamera == element);
        if (!isMain && element->baseObject->name != ".EditorCamera") {
            if (ImGui::Button("Make Main Camera")) {
                Camera::mainCamera = element;
            }
        } else if(element->baseObject->name != ".EditorCamera") {
            ImGui::Text("This is the Main Camera");
        }
        else
        {
            ImGui::Text("Editor Camera can't be main camera");
        }

        ImGui::Separator();
        // Render Scale
        float renderScale = element->GetRenderScale();
        if (ImGui::DragFloat("Render Scale", &renderScale, 0.1f))
            element->SetRenderScale(renderScale);

        ImGui::Separator();

        // Projection
        int projIndex = (element->GetProjection() == ProjectionType::Orthographic) ? 0 : 1;
        const char* projItems[] = { "Orthographic", "Perspective" };
        if (ImGui::Combo("Projection", &projIndex, projItems, IM_ARRAYSIZE(projItems)))
            element->SetProjection(projIndex == 0 ? ProjectionType::Orthographic
                                                : ProjectionType::Perspective);

        // Clipping Planes
        float nearCP = element->GetNearClippingPlane();
        if (ImGui::DragFloat("Near Clipping Plane", &nearCP, 0.1f))
            element->SetNearClippingPlane(nearCP);

        float farCP = element->GetFarClippingPlane();
        if (ImGui::DragFloat("Far Clipping Plane", &farCP, 0.1f))
            element->SetFarClippingPlane(farCP);

        // Field of View (only relevant for Perspective)
        const bool isPerspective = (element->GetProjection() == ProjectionType::Perspective);
        if (!isPerspective) ImGui::BeginDisabled();
        float fov = element->GetFov();
        if (ImGui::DragFloat("Field of View (deg)", &fov, 0.1f))
            element->SetFov(fov);
        if (!isPerspective) ImGui::EndDisabled();

        Scene* curScene = HirearchieView::currentScene;
        ImGui::SeparatorText("Layers To Render");
        if (curScene == nullptr)
        {
            ImGui::TextDisabled("No active scene available.");
            return;
        }

        if (ImGui::BeginChild("LayersToRender", ImVec2(0, 170), ImGuiChildFlags_Borders))
        {
            const int layerCount = curScene->GetLayerCount();
            if (layerCount <= 0)
            {
                ImGui::TextDisabled("Scene has no layers.");
            }
            else
            {
                for (int i = 0; i < layerCount; i++)
                {
                    Layer* layer = curScene->GetLayerAt(i);
                    if (layer == nullptr) continue;
                    if (!layer->IsVisual()) continue;

                    const uuids::uuid& layerID = layer->GetID();
                    auto it = std::find(element->layersNotToRender.begin(), element->layersNotToRender.end(), layerID);
                    bool shouldRenderLayer = (it == element->layersNotToRender.end());

                    const std::string checkBoxLabel = layer->GetName() + "##layer_to_render_" + std::to_string(i);
                    if (ImGui::Checkbox(checkBoxLabel.c_str(), &shouldRenderLayer))
                    {
                        if (shouldRenderLayer)
                        {
                            auto removeIt = std::find(element->layersNotToRender.begin(), element->layersNotToRender.end(), layerID);
                            if (removeIt != element->layersNotToRender.end())
                            {
                                element->layersNotToRender.erase(removeIt);
                            }
                        }
                        else if (it == element->layersNotToRender.end())
                        {
                            element->layersNotToRender.push_back(layerID);
                        }
                    }
                }
            }
        }
        ImGui::EndChild();


    }
    void ElementDrawer::Draw(ParticleSystem *element, const bool &debug)
    {
        float indent = 15.0f;
        auto OpeningAngleDeg = [](float conePlane) -> float {
            float cosA = std::clamp(conePlane * 2.0f - 1.0f, -1.0f, 1.0f);
            return std::acos(cosA) * (180.0f / TSE_PI);
        };
        auto ClampPositive = [](float& v, float minv = 0.0f) { if (v < minv) v = minv; };

        // =========================
        //        MISC
        // =========================
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
        if (ImGui::CollapsingHeader("Misc", ImGuiTreeNodeFlags_DefaultOpen))
        {
            ImGui::Indent(20.0f);

            int pc = static_cast<int>(element->particleCount);
            if (ImGui::DragInt("Max Particles", &pc, 1.0f, 0, 100000)) {
                if (pc < 0) pc = 0;
                element->particleCount = static_cast<uint>(pc);
            }

            ImGui::Checkbox("Start with Simulated Particles", &element->startWithSimulatedParicles);
            if (ImGui::IsItemHovered()) ImGui::SetTooltip("Wenn aktiv, wird beim Start bereits ein gefüllter Partikelpuffer simuliert.");

            ImGui::Unindent(20.0f);
            ImGui::Separator();
        }

        // =========================
        //   START CONDITIONS
        // =========================
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
        if (ImGui::CollapsingHeader("Start Conditions", ImGuiTreeNodeFlags_DefaultOpen))
        {
            ImGui::Indent(20.0f);

            if (ImGui::TreeNodeEx("Rotation (Start)", ImGuiTreeNodeFlags_DefaultOpen))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Random Rotation Direction", &element->startWithRandomRotationDirection);
                if (!element->startWithRandomRotationDirection) {
                    int dirIdx = (element->rotationDirection >= 0.0f) ? 1 : 0;
                    const char* dirItems[] = { "-1 (CCW)", "+1 (CW)" };
                    if (ImGui::Combo("Rotation Direction", &dirIdx, dirItems, IM_ARRAYSIZE(dirItems))) {
                        element->rotationDirection = (dirIdx == 1) ? 1.0f : -1.0f;
                    }
                } else {
                    ImGui::BeginDisabled();
                    float dummy = element->rotationDirection;
                    ImGui::InputFloat("Rotation Direction", &dummy);
                    ImGui::EndDisabled();
                }

                ImGui::Checkbox("Random Start Rotation", &element->startWithRandomRotation);
                if (element->startWithRandomRotation) {
                    ImGui::DragFloat("Min Rotation (rad)", &element->minRotationRad, 0.01f);
                    ImGui::DragFloat("Max Rotation (rad)", &element->maxrotationRad, 0.01f);
                    if (element->maxrotationRad < element->minRotationRad) std::swap(element->minRotationRad, element->maxrotationRad);
                } else {
                    ImGui::DragFloat("Start Rotation (rad)", &element->maxrotationRad, 0.01f);
                    ImGui::BeginDisabled(); ImGui::DragFloat("Min Rotation (rad)", &element->minRotationRad, 0.01f); ImGui::EndDisabled();
                }

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            if (ImGui::TreeNode("Size (Start)"))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Random Start Size", &element->startWithRandomSize);
                if (element->startWithRandomSize) {
                    if (ImGui::DragFloat("Min Size", &element->minSize, 0.01f)) { ClampPositive(element->minSize, 0.0f); }
                    if (ImGui::DragFloat("Max Size", &element->maxSize, 0.01f)) { ClampPositive(element->maxSize, 0.0f); }
                    if (element->maxSize < element->minSize) std::swap(element->minSize, element->maxSize);
                } else {
                    if (ImGui::DragFloat("Start Size", &element->maxSize, 0.01f)) { ClampPositive(element->maxSize, 0.0f); }
                    ImGui::BeginDisabled(); ImGui::DragFloat("Min Size", &element->minSize, 0.01f); ImGui::EndDisabled();
                }

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            if (ImGui::TreeNode("Lifetime (Start)"))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Random Start Lifetime", &element->startWithRandomLifetime);
                if (element->startWithRandomLifetime) {
                    if (ImGui::DragFloat("Min Lifetime (s)", &element->minLifetime, 0.01f)) { ClampPositive(element->minLifetime, 0.0f); }
                    if (ImGui::DragFloat("Max Lifetime (s)", &element->maxLifetime, 0.01f)) { ClampPositive(element->maxLifetime, 0.0f); }
                    if (element->maxLifetime < element->minLifetime) std::swap(element->minLifetime, element->maxLifetime);
                } else {
                    if (ImGui::DragFloat("Lifetime (s)", &element->maxLifetime, 0.01f)) { ClampPositive(element->maxLifetime, 0.0f); }
                    ImGui::BeginDisabled(); ImGui::DragFloat("Min Lifetime (s)", &element->minLifetime, 0.01f); ImGui::EndDisabled();
                }

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            ImGui::Unindent(20.0f);
            ImGui::Separator();
        }

        // =========================
        //  LIFETIME CONDITIONS
        // =========================
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
        if (ImGui::CollapsingHeader("Lifetime Conditions", ImGuiTreeNodeFlags_DefaultOpen))
        {
            ImGui::Indent(20.0f);

            if (ImGui::TreeNode("Color over Lifetime"))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Enable Color over Lifetime", &element->changeColorOverLifetime);
                // Start immer editierbar
                ImGui::ColorEdit4("Start Color", &element->startColor.r, ImGuiColorEditFlags_Float);
                // End nur wenn aktiviert
                if (!element->changeColorOverLifetime) ImGui::BeginDisabled();
                ImGui::ColorEdit4("End Color",   &element->endColor.r,   ImGuiColorEditFlags_Float);
                if (!element->changeColorOverLifetime) ImGui::EndDisabled();

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            if (ImGui::TreeNode("Speed over Lifetime"))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Enable Speed over Lifetime", &element->changeSpeedOverLifetime);
                // Start immer frei
                ImGui::DragFloat("Start Speed", &element->startSpeed, 0.01f);
                // End nur bei aktiv
                if (!element->changeSpeedOverLifetime) ImGui::BeginDisabled();
                ImGui::DragFloat("End Speed",   &element->endSpeed,   0.01f);
                if (!element->changeSpeedOverLifetime) ImGui::EndDisabled();

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            if (ImGui::TreeNode("Rotation Speed over Lifetime"))
            {
                ImGui::Indent(16.0f);

                ImGui::Checkbox("Enable RotationSpeed over Lifetime", &element->changeRotationspeedOverLifetime);
                // Start immer frei
                ImGui::DragFloat("Start RotSpeed", &element->startRotationSpeed, 0.01f);
                // End nur bei aktiv
                if (!element->changeRotationspeedOverLifetime) ImGui::BeginDisabled();
                ImGui::DragFloat("End RotSpeed",   &element->endRotationSpeed,   0.01f);
                if (!element->changeRotationspeedOverLifetime) ImGui::EndDisabled();

                ImGui::Unindent(16.0f);
                ImGui::TreePop();
            }

            ImGui::Unindent(20.0f);
            ImGui::Separator();
        }

        // =========================
        //      SPAWN AREA
        // =========================
        ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
        if (ImGui::CollapsingHeader("Spawn Area", ImGuiTreeNodeFlags_DefaultOpen))
        {
            ImGui::Indent(20.0f);

            ImGui::DragFloat3("Offset (world)", &element->offset.x, 0.01f);

            ImGui::DragFloat3("Forward", &element->forward.x, 0.01f);
            ImGui::SameLine();
            if (ImGui::SmallButton("Normalize##fwd")) {
                element->forward.NormalizeSafe(Vector3::forward);
            }

            if (ImGui::DragFloat("Radius", &element->radius, 0.01f)) {
                if (element->radius < 0.0f) element->radius = 0.0f;
            }

            if (ImGui::SliderFloat("Cone Plane", &element->conePlane, 0.0f, 1.0f, "%.3f")) {
                element->conePlane = std::clamp(element->conePlane, 0.0f, 1.0f);
            }

            float angle = OpeningAngleDeg(element->conePlane);
            ImGui::Text("Opening Angle: %.2f deg", angle);

            const char* mode = "Forward Cone";
            if (element->conePlane == 1.0f) mode = "Full Sphere";
            else if (element->conePlane <= 0.5f) mode = "Forward Cone";
            else mode = "Inverse Cone";
            ImGui::Text("Mode (derived): %s", mode);

            if (debug) {
                ImGui::Separator();
                ImGui::TextDisabled("Debug:");
                ImGui::BulletText("Forward len^2: %.6f", element->forward.LengthSqr());
            }

            ImGui::Unindent(20.0f);
        }
    }
    void ElementDrawer::Draw(TileMap *element, const bool &debug)
    {
        int orderIndex = static_cast<int>(element->order);
        const char* orderItems[] = { "TopRight", "TopLeft", "BottomRight", "BottomLeft" };
        if (ImGui::Combo("Order", &orderIndex, orderItems, IM_ARRAYSIZE(orderItems)))
        {
            element->order = static_cast<SortingOrder>(orderIndex);
            for (auto& [_, chunk] : element->chunks)
            {
                chunk.SetOrdering(element->order);
            }
            element->DirtyAll();
        }

        ImGui::BeginDisabled();
        ImGui::DragInt("Chunk Size", &element->chunkSize, 1.0f);
        ImGui::EndDisabled();

        Vector2 nextLine = element->GetNextLineOffset();
        if (ImGui::DragFloat2("Next Line Offset", &nextLine.x, 0.01f))
        {
            element->SetNextLineOffset(nextLine);
        }

        ImGui::DragFloat2("Sprite Scale", &element->SpriteScale.x, 0.01f);

        if (debug)
        {
            Rect bounds = element->GetBounds();
            ImGui::Separator();
            ImGui::TextDisabled("Bounds");
            ImGui::BeginDisabled();
            ImGui::InputFloat2("Min", &bounds.p1.x);
            ImGui::InputFloat2("Max", &bounds.p2.x);
            ImGui::EndDisabled();

            ImGui::TextDisabled(("Chunk Count: " + std::to_string(element->GetChunkCount())).c_str());
        }
    }
    void ElementDrawer::DrawAudioClipCompact(AudioClip *element, const bool &debug, const std::string &label)
    {
        float item_spacing = ImGui::GetStyle().ItemSpacing.x;
        ImVec2 label_size = ImGui::CalcTextSize(label.c_str());

        float available_width = ImGui::GetContentRegionAvail().x;
        float field_width = available_width - label_size.x - item_spacing;

        ImVec2 field_size = ImVec2(field_width, label_size.y + 4);

        ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);

        ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

        ImGui::SetCursorPos(ImVec2(2, 2));
        ImGui::TextUnformatted(element->name.c_str());

        ImGui::EndChild();

        ImGui::PopStyleVar();
        ImGui::PopStyleColor();

        ImGui::SameLine();
        ImVec2 cursorCurrent = ImGui::GetCursorPos();
        cursorCurrent.y += 2;
        ImGui::SetCursorPos(cursorCurrent);
        ImGui::TextUnformatted(label.c_str());
    }
    void ElementDrawer::DrawAudioClipNormal(AudioClip *element, const bool &debug, const std::string &label)
    {
        //TODO implement
    }
    void ElementDrawer::DrawImageAnimationSetCompact(ImageAnimationSet *element, const bool &debug, const std::string &label)
    {
        float item_spacing = ImGui::GetStyle().ItemSpacing.x;
        ImVec2 label_size = ImGui::CalcTextSize(label.c_str());

        float available_width = ImGui::GetContentRegionAvail().x;
        float field_width = available_width - label_size.x - item_spacing;

        ImVec2 field_size = ImVec2(field_width, label_size.y + 4);

        ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);

        ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

        ImGui::SetCursorPos(ImVec2(2, 2));
        ImGui::TextUnformatted(element->Name.c_str());

        ImGui::EndChild();

        ImGui::PopStyleVar();
        ImGui::PopStyleColor();

        ImGui::SameLine();
        ImVec2 cursorCurrent = ImGui::GetCursorPos();
        cursorCurrent.y += 2;
        ImGui::SetCursorPos(cursorCurrent);
        ImGui::TextUnformatted(label.c_str());
    }
    void ElementDrawer::DrawImageAnimationSetNormal(ImageAnimationSet *element, const bool &debug, const std::string &label)
    {
        InputText("Name", element->Name);
        ImGui::InputFloat("Frame Time", &element->frameTime);
        ImGui::SeparatorText("Sprites");
        BeginList("SpriteList");
        if(ListAddBtn())
        {
            element->Sprites.push_back(nullptr);
        }
        auto it = element->Sprites.begin();
        for (int i = 0; i < element->Sprites.size(); i++)
        {
            BeginListItem("subcomponent##" + std::to_string(i),65);
            Draw(element->Sprites[i],debug, std::to_string(i), true);
            EndListItem();
            if(ListItemXBotton("x##" + std::to_string(i)))
            {
                auto it2 = it;
                it--;
                element->Sprites.erase(it2);
                i--;
            }
            it++;
        }
        EndList();
    }
    void ElementDrawer::DrawMeshCompact(Mesh *element, const bool &debug, const std::string &label)
    {
        float item_spacing = ImGui::GetStyle().ItemSpacing.x;
        ImVec2 label_size = ImGui::CalcTextSize(label.c_str());

        float available_width = ImGui::GetContentRegionAvail().x;
        float field_width = available_width - label_size.x - item_spacing;

        ImVec2 field_size = ImVec2(field_width, label_size.y + 4);

        ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);

        ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

        ImGui::SetCursorPos(ImVec2(2, 2));
        ImGui::TextUnformatted(element->name.c_str());

        ImGui::EndChild();

        ImGui::PopStyleVar();
        ImGui::PopStyleColor();

        ImGui::SameLine();
        ImVec2 cursorCurrent = ImGui::GetCursorPos();
        cursorCurrent.y += 2;
        ImGui::SetCursorPos(cursorCurrent);
        ImGui::TextUnformatted(label.c_str());
    }
    void ElementDrawer::DrawMeshNormal(Mesh *element, const bool &debug, const std::string &label)
    {
        ImGui::Text(("Name: " + element->name).c_str());
        if(debug)
        {
            //ImGui::TextDisabled(("ID: " + to_string(element->id)).c_str());
        }
        ImGui::Separator();
        ImGui::Text(("Vectex Count: " + std::to_string(element->vertecies.size())).c_str());
        ImGui::Text(("Index Count: " + std::to_string(element->indecies.size())).c_str());
        ImGui::Text(("UV Count: " + std::to_string(element->uvs.size())).c_str());
        ImGui::Indent(20.0f);
        if(ImGui::CollapsingHeader("Vertecies"))
        {
            ImGui::PushID("Verts");
            ImGui::BeginDisabled();
            for (int i = 0; i < element->vertecies.size(); i++)
            {
                ImGui::InputFloat3(std::to_string(i).c_str(), &element->vertecies[i].x);
            }
            ImGui::EndDisabled();
            ImGui::PopID();
        }
        if(ImGui::CollapsingHeader("Indecies"))
        {
            ImGui::PushID("Inds");
            ImGui::BeginDisabled();
            for (int i = 0; i < element->indecies.size(); i++)
            {
                int val = element->indecies[i];
                ImGui::InputInt(std::to_string(i).c_str(), &val);
            }
            ImGui::EndDisabled();
            ImGui::PopID();
        }
        if(ImGui::CollapsingHeader("UVs"))
        {
            ImGui::PushID("Uvs");
            ImGui::BeginDisabled();
            for (int i = 0; i < element->uvs.size(); i++)
            {
                ImGui::InputFloat2(std::to_string(i).c_str(), &element->uvs[i].x);
            }
            ImGui::EndDisabled();
            ImGui::PopID();
        }
        ImGui::Unindent(20.0f);

    }
    void ElementDrawer::DrawSpriteCompact(Sprite *element, const bool &debug, const std::string &label)
    {
        float item_spacing = ImGui::GetStyle().ItemSpacing.x;
        ImVec2 label_size = ImGui::CalcTextSize(label.c_str());

        float available_width = ImGui::GetContentRegionAvail().x;
        float field_width = available_width - label_size.x - item_spacing;

        ImVec2 field_size = ImVec2(field_width, 60);

        Rect r = element->GetUVRect();
        float ymultiplyer = (element->GetTexture()->Height() * r.height()) / (element->GetTexture()->Width() * r.width());

        ImVec2 texSize (field_size.y - 2, (field_size.y - 2) * ymultiplyer);

        ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);

        ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

        ImGui::SetCursorPos(ImVec2(1,(60-texSize.y) / 2));
        ImGui::Image(element->GetTexture()->GetTextureId(), texSize, {r.p1.x,r.p2.y}, {r.p2.x,r.p1.y});

        ImGui::EndChild();

        ImGui::PopStyleVar();
        ImGui::PopStyleColor();

        ImGui::SameLine();
        ImVec2 cursorCurrent = ImGui::GetCursorPos();
        cursorCurrent.y += (60-label_size.y) / 2;
        ImGui::SetCursorPos(cursorCurrent);
        ImGui::TextUnformatted(label.c_str());
    }
    void ElementDrawer::DrawSpriteNormal(Sprite *element, const bool &debug, const std::string &label)
    {
        Rect& r = element->GetUVRect();
        ImGui::InputFloat2("UV1", &r.p1.x);
        ImGui::InputFloat2("UV2", &r.p2.x);
        if(debug)
        {
            Draw(element->GetTexture(), debug, "Texture", true);
        }
        ImGui::Separator();
        float available_width = ImGui::GetContentRegionAvail().x;
        float ymultiplyer = (element->GetTexture()->Height() * r.height()) / (element->GetTexture()->Width() * r.width());

        ImVec2 texSize (available_width, (available_width) * ymultiplyer);
        ImGui::Image(element->GetTexture()->GetTextureId(), texSize, {r.p1.x,r.p2.y}, {r.p2.x,r.p1.y});
    }
    void ElementDrawer::DrawTextureCompact(Texture *element, const bool &debug, const std::string &label)
    {
        float item_spacing = ImGui::GetStyle().ItemSpacing.x;
        ImVec2 label_size = ImGui::CalcTextSize(label.c_str());

        float available_width = ImGui::GetContentRegionAvail().x;
        float field_width = available_width - label_size.x - item_spacing;

        ImVec2 field_size = ImVec2(field_width, 60);

        float ymultiplyer = element->Height() / element->Width();

        ImVec2 texSize (field_size.y - 2, (field_size.y - 2) * ymultiplyer);

        ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);

        ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

        ImGui::SetCursorPos(ImVec2(1,(60-texSize.y) / 2));
        ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
        ImGui::SameLine();
        ImGui::SetCursorPos(ImVec2(field_size.y + 1,(60-label_size.y) / 2));
        ImGui::TextUnformatted(element->name.c_str());

        ImGui::EndChild();

        ImGui::PopStyleVar();
        ImGui::PopStyleColor();

        ImGui::SameLine();
        ImVec2 cursorCurrent = ImGui::GetCursorPos();
        cursorCurrent.y += (60-label_size.y) / 2;
        ImGui::SetCursorPos(cursorCurrent);
        ImGui::TextUnformatted(label.c_str());
    }
    void ElementDrawer::DrawTextureNormal(Texture *element, const bool &debug, const std::string& label)
    {
        ImGui::TextUnformatted(element->name.c_str());
        if(debug)
        {
            ImGui::Separator();
            ImGui::TextDisabled(("Width: " + std::to_string(element->Width())).c_str());
            ImGui::TextDisabled(("Height: " + std::to_string(element->Height())).c_str());
            ImGui::TextDisabled(("BPP: " + std::to_string(element->bpp())).c_str());
            ImGui::TextDisabled(("Chanels: " + std::to_string(element->Chanels())).c_str());
            ImGui::Separator();
            ImGui::TextDisabled(("TextureID: " + std::to_string(element->GetTextureId())).c_str());
        }
        ImGui::Separator();
        float available_width = ImGui::GetContentRegionAvail().x;
        float ymultiplyer = element->Height() / element->Width();

        ImVec2 texSize (available_width, (available_width) * ymultiplyer);
        ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
    }

} // namespace TSE::EDITOR
