#include "template_editor.hpp"
#include "core/common/utils.hpp"
#include "core/config/config.hpp"
#include "core/palette/color_keys.hpp"
#include "core/theme/theme_template.hpp"
#include "gui/theme/app_theme.hpp"
#include "gui/widgets/colors.hpp"
#include "gui/widgets/dialogs.hpp"
#include "gui/ui_manager.hpp"
#include "imgui.h"
#include <algorithm>
#include <cmath>
#include <filesystem>
#include <fstream>
#include <ranges>

namespace
{
const std::vector<std::string> COLOR_FORMATS = {
    "hex", "hex_stripped", "hexa", "hexa_stripped", "r", "g", "b", "a", "rgb", "rgba", "h", "s",
    "l",   "hsl",          "hsla"};
}

template_editor::template_editor(clrsync::gui::ui_manager* ui_mgr)
    : m_ui_manager(ui_mgr)
{
    m_control_state.name = "new_template";

    update_autocomplete_colors();

    TextEditor::LanguageDefinition lang;
    lang.mName = "Template";

    lang.mCommentStart = "/*";
    lang.mCommentEnd = "*/";
    lang.mSingleLineComment = "#";

    lang.mTokenRegexStrings.push_back(std::make_pair<std::string, TextEditor::PaletteIndex>(
        "\\{[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?\\}",
        TextEditor::PaletteIndex::KnownIdentifier));

    lang.mTokenRegexStrings.push_back(std::make_pair<std::string, TextEditor::PaletteIndex>(
        "\"([^\"]*)\"", TextEditor::PaletteIndex::String));
    lang.mTokenRegexStrings.push_back(std::make_pair<std::string, TextEditor::PaletteIndex>(
        "'([^']*)'", TextEditor::PaletteIndex::String));

    m_editor.SetLanguageDefinition(lang);
    m_editor.SetText("# Enter your template here\n# Use {color_key} for color variables\n# "
                     "Examples: {color.hex}, {color.rgb}, {color.r}\n\n");
    m_editor.SetShowWhitespaces(false);

    setup_callbacks();
}

void template_editor::setup_callbacks()
{
    m_callbacks.on_new = [this]() { new_template(); };
    m_callbacks.on_save = [this]() { save_template(); };
    m_callbacks.on_delete = [this]() { delete_template(); };
    m_callbacks.on_enabled_changed = [this](bool enabled) {
        m_template_controller.set_template_enabled(m_control_state.name, enabled);
    };
    m_callbacks.on_browse_input = [this](const std::string& path) -> std::string {
        return m_ui_manager->open_file_dialog("Select Template File", path);
    };
    m_callbacks.on_browse_output = [this](const std::string& path) -> std::string {
        return m_ui_manager->save_file_dialog("Select Output File", path);
    };
    m_callbacks.on_input_path_changed = [this](const std::string& path) {
        m_template_controller.set_template_input_path(m_control_state.name, path);
    };
    m_callbacks.on_output_path_changed = [this](const std::string& path) {
        m_template_controller.set_template_output_path(m_control_state.name, path);
    };
    m_callbacks.on_reload_command_changed = [this](const std::string& cmd) {
        m_template_controller.set_template_reload_command(m_control_state.name, cmd);
    };
}

void template_editor::update_autocomplete_colors()
{
    const auto &t = clrsync::gui::theme::current_theme();
    m_autocomplete_bg_color = t.autocomplete_bg();
    m_autocomplete_border_color = t.autocomplete_border();
    m_autocomplete_selected_color = t.autocomplete_selected();
    m_autocomplete_text_color = t.autocomplete_text();
    m_autocomplete_selected_text_color = t.autocomplete_selected_text();
    m_autocomplete_dim_text_color = t.autocomplete_dim_text();
}

void template_editor::apply_current_palette(const clrsync::core::palette &pal)
{
    m_current_palette = pal;
    auto colors = pal.colors();
    if (colors.empty())
        return;

    using namespace clrsync::gui::theme;

    auto get_color_u32 = [&](const std::string &key, const std::string &fallback = "") -> uint32_t {
        return clrsync::gui::widgets::palette_color_u32(pal, key, fallback);
    };

    auto palette = m_editor.GetPalette();

    palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("editor_main", "foreground");
    palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("editor_command", "accent");
    palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("editor_warning", "warning");
    palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("editor_string", "success");
    palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("editor_string", "success");
    palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32("editor_main", "foreground");
    palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32("editor_emphasis", "accent");
    palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("editor_main", "foreground");
    palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("editor_link", "info");
    palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32("editor_link", "info");

    palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32("editor_comment", "editor_inactive");
    palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32("editor_comment", "editor_inactive");

    palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32("editor_background", "background");
    palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor", "accent");

    palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32("editor_selected", "surface_variant");
    palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("editor_error", "error");
    palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("editor_error", "error");

    palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32("editor_line_number", "editor_inactive");
    palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
    palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
    palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32("border_focused", "border");

    m_editor.SetPalette(palette);

    update_autocomplete_colors();
}

void template_editor::update_autocomplete_suggestions()
{
    m_autocomplete_suggestions.clear();

    auto cursor = m_editor.GetCursorPosition();
    std::string line = m_editor.GetCurrentLineText();
    int col = cursor.mColumn;

    // Check if inside '{'
    int brace_pos = -1;
    for (int i = col - 1; i >= 0; --i)
    {
        if (i < (int)line.length())
        {
            if (line[i] == '{')
            {
                brace_pos = i;
                break;
            }
            else if (line[i] == '}' || line[i] == ' ' || line[i] == '\t')
            {
                break;
            }
        }
    }

    if (brace_pos < 0)
    {
        m_show_autocomplete = false;
        m_autocomplete_dismissed = false;
        return;
    }

    m_autocomplete_end_brace_pos = -1;
    for (int i = col; i < (int)line.length(); ++i)
    {
        if (line[i] == '}')
        {
            m_autocomplete_end_brace_pos = i;
            break;
        }
        else if (line[i] == '{' || line[i] == ' ' || line[i] == '\t')
        {
            break;
        }
    }

    if (m_autocomplete_dismissed)
    {
        bool should_reset_dismissal = false;

        if (cursor.mLine != m_dismiss_position.mLine || brace_pos != m_dismiss_brace_pos ||
            abs(cursor.mColumn - m_dismiss_position.mColumn) > 3)
        {
            should_reset_dismissal = true;
        }

        if (should_reset_dismissal)
        {
            m_autocomplete_dismissed = false;
        }
        else
        {
            m_show_autocomplete = false;
            return;
        }
    }

    m_autocomplete_prefix = line.substr(brace_pos + 1, col - brace_pos - 1);
    m_autocomplete_start_pos = TextEditor::Coordinates(cursor.mLine, brace_pos + 1);

    size_t dot_pos = m_autocomplete_prefix.find('.');

    if (dot_pos != std::string::npos)
    {
        std::string color_key = m_autocomplete_prefix.substr(0, dot_pos);
        std::string format_prefix = m_autocomplete_prefix.substr(dot_pos + 1);

        bool valid_key = false;
        for (size_t i = 0; i < clrsync::core::NUM_COLOR_KEYS; ++i)
        {
            if (clrsync::core::COLOR_KEYS[i] == color_key)
            {
                valid_key = true;
                break;
            }
        }

        if (valid_key)
        {
            for (const auto &fmt : COLOR_FORMATS)
            {
                if (format_prefix.empty() || fmt.find(format_prefix) == 0)
                {
                    m_autocomplete_suggestions.push_back(color_key + "." + fmt);
                }
            }
        }
    }
    else
    {
        std::vector<std::pair<std::string, int>> scored_suggestions;
        
        for (size_t i = 0; i < clrsync::core::NUM_COLOR_KEYS; ++i)
        {
            std::string key = clrsync::core::COLOR_KEYS[i];
            
            if (m_autocomplete_prefix.empty())
            {
                scored_suggestions.push_back({key, 0});
            }
            else
            {
                if (key.find(m_autocomplete_prefix) == 0)
                {
                    scored_suggestions.push_back({key, 100});
                }
                else
                {
                    size_t pos = key.find("_" + m_autocomplete_prefix);
                    if (pos != std::string::npos)
                    {
                        scored_suggestions.push_back({key, 50});
                    }
                    else if (key.find(m_autocomplete_prefix) != std::string::npos)
                    {
                        scored_suggestions.push_back({key, 25});
                    }
                }
            }
        }
        
        std::sort(scored_suggestions.begin(), scored_suggestions.end(),
                  [](const auto &a, const auto &b) {
                      if (a.second != b.second)
                          return a.second > b.second;
                      return a.first < b.first;
                  });
        
        for (const auto &[key, score] : scored_suggestions)
        {
            m_autocomplete_suggestions.push_back(key);
        }
    }

    m_show_autocomplete = !m_autocomplete_suggestions.empty();
    if (m_show_autocomplete && m_autocomplete_selected >= (int)m_autocomplete_suggestions.size())
    {
        m_autocomplete_selected = 0;
    }
}

void template_editor::render_autocomplete(const ImVec2 &editor_pos)
{
    if (!m_show_autocomplete || m_autocomplete_suggestions.empty())
        return;

    float line_height = ImGui::GetTextLineHeightWithSpacing();
    float char_width = ImGui::GetFontSize() * 0.5f;
    auto cursor = m_editor.GetCursorPosition();

    const float line_number_width = 50.0f;

    ImVec2 popup_pos;
    popup_pos.x =
        editor_pos.x + line_number_width + (m_autocomplete_start_pos.mColumn * char_width);
    popup_pos.y = editor_pos.y + ((cursor.mLine + 1) * line_height);

    ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Always);
    
    float max_width = 350.0f;
    float min_width = 250.0f;
    ImGui::SetNextWindowSize(ImVec2(max_width, 0));

    ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
                             ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
                             ImGuiWindowFlags_NoFocusOnAppearing |
                             ImGuiWindowFlags_AlwaysAutoResize;

    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8));
    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f);
    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 3));
    ImGui::PushStyleColor(ImGuiCol_WindowBg, m_autocomplete_bg_color);
    ImGui::PushStyleColor(ImGuiCol_Border, m_autocomplete_border_color);

    if (ImGui::Begin("##autocomplete", nullptr, flags))
    {
        ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
        if (m_autocomplete_prefix.find('.') != std::string::npos)
            ImGui::Text("Color Formats");
        else
            ImGui::Text("Color Keys (%d)", (int)m_autocomplete_suggestions.size());
        ImGui::PopStyleColor();
        ImGui::Separator();

        int max_visible = std::min((int)m_autocomplete_suggestions.size(), 12);
        
        if (m_autocomplete_selected >= max_visible)
        {
            m_autocomplete_selected = max_visible - 1;
        }

        for (int i = 0; i < max_visible; ++i)
        {
            const auto &suggestion = m_autocomplete_suggestions[i];
            bool is_selected = (i == m_autocomplete_selected);

            if (is_selected)
            {
                ImVec4 selected_hover = m_autocomplete_selected_color;
                selected_hover.w = std::min(selected_hover.w + 0.1f, 1.0f);
                ImGui::PushStyleColor(ImGuiCol_Header, m_autocomplete_selected_color);
                ImGui::PushStyleColor(ImGuiCol_HeaderHovered, selected_hover);
                ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_selected_text_color);
            }
            else
            {
                ImVec4 normal_bg = m_autocomplete_bg_color;
                normal_bg.w = 0.5f;
                ImVec4 hover_bg = m_autocomplete_selected_color;
                hover_bg.w = 0.3f;
                ImGui::PushStyleColor(ImGuiCol_Header, normal_bg);
                ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hover_bg);
                ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_text_color);
            }

            std::string display_text = "  " + suggestion;

            std::string color_key = suggestion;
            size_t dot_pos = suggestion.find('.');
            if (dot_pos != std::string::npos)
            {
                color_key = suggestion.substr(0, dot_pos);
            }

            bool has_color = false;
            clrsync::core::color palette_color;
            if (m_current_palette.colors().count(color_key) > 0)
            {
                has_color = true;
                palette_color = m_current_palette.colors().at(color_key);
            }

            if (ImGui::Selectable(display_text.c_str(), is_selected, ImGuiSelectableFlags_None,
                                  ImVec2(0, 0)))
            {
                auto start = m_autocomplete_start_pos;
                auto cursor_pos = m_editor.GetCursorPosition();
                
                TextEditor::Coordinates end;
                if (m_autocomplete_end_brace_pos >= 0)
                {
                    end = TextEditor::Coordinates(cursor_pos.mLine, m_autocomplete_end_brace_pos);
                }
                else
                {
                    end = cursor_pos;
                }
                
                std::string insert_text = suggestion;
                if (m_autocomplete_end_brace_pos < 0)
                {
                    insert_text += "}";
                }
                
                const char* old_clipboard = ImGui::GetClipboardText();
                std::string saved_clipboard = old_clipboard ? old_clipboard : "";
                
                ImGui::SetClipboardText(insert_text.c_str());
                
                m_editor.SetSelection(start, end);
                m_editor.Paste();
                
                ImGui::SetClipboardText(saved_clipboard.c_str());
                
                m_show_autocomplete = false;
                m_autocomplete_dismissed = false;
            }

            if (has_color)
            {
                ImVec2 item_min = ImGui::GetItemRectMin();
                ImVec2 item_max = ImGui::GetItemRectMax();
                
                const float preview_size = ImGui::GetTextLineHeight() * 0.7f;
                const float padding = 4.0f;
                
                ImVec2 preview_pos;
                preview_pos.x = item_max.x - preview_size - padding;
                preview_pos.y = item_min.y + (item_max.y - item_min.y - preview_size) * 0.5f;
                
                ImDrawList* draw_list = ImGui::GetWindowDrawList();
                
                auto rgba = palette_color.to_rgba();
                ImU32 color_u32 = IM_COL32(rgba.r, rgba.g, rgba.b, rgba.a);
                
                float r = rgba.r / 255.0f;
                float g = rgba.g / 255.0f;
                float b = rgba.b / 255.0f;
                
                r = (r <= 0.03928f) ? r / 12.92f : std::pow((r + 0.055f) / 1.055f, 2.4f);
                g = (g <= 0.03928f) ? g / 12.92f : std::pow((g + 0.055f) / 1.055f, 2.4f);
                b = (b <= 0.03928f) ? b / 12.92f : std::pow((b + 0.055f) / 1.055f, 2.4f);
                
                float luminance = 0.2126f * r + 0.7152f * g + 0.0722f * b;
                
                ImVec4 bg_color = is_selected ? m_autocomplete_selected_color : m_autocomplete_bg_color;
                float bg_r = bg_color.x;
                float bg_g = bg_color.y;
                float bg_b = bg_color.z;
                
                bg_r = (bg_r <= 0.03928f) ? bg_r / 12.92f : std::pow((bg_r + 0.055f) / 1.055f, 2.4f);
                bg_g = (bg_g <= 0.03928f) ? bg_g / 12.92f : std::pow((bg_g + 0.055f) / 1.055f, 2.4f);
                bg_b = (bg_b <= 0.03928f) ? bg_b / 12.92f : std::pow((bg_b + 0.055f) / 1.055f, 2.4f);
                
                float bg_luminance = 0.2126f * bg_r + 0.7152f * bg_g + 0.0722f * bg_b;
                
                float contrast = (std::max(luminance, bg_luminance) + 0.05f) / 
                                (std::min(luminance, bg_luminance) + 0.05f);
                
                if (contrast < 2.0f)
                {
                    ImU32 contrast_bg = (bg_luminance > 0.5f) ? IM_COL32(0, 0, 0, 180) : IM_COL32(255, 255, 255, 180);
                    const float bg_padding = 2.0f;
                    draw_list->AddRectFilled(
                        ImVec2(preview_pos.x - bg_padding, preview_pos.y - bg_padding),
                        ImVec2(preview_pos.x + preview_size + bg_padding, preview_pos.y + preview_size + bg_padding),
                        contrast_bg,
                        2.0f
                    );
                }
                
                draw_list->AddRectFilled(
                    preview_pos,
                    ImVec2(preview_pos.x + preview_size, preview_pos.y + preview_size),
                    color_u32,
                    2.0f
                );
                
                ImU32 border_color = IM_COL32(255, 255, 255, 60);
                draw_list->AddRect(
                    preview_pos,
                    ImVec2(preview_pos.x + preview_size, preview_pos.y + preview_size),
                    border_color,
                    2.0f,
                    0,
                    1.0f
                );
            }

            ImGui::PopStyleColor(3);

            if (is_selected && ImGui::IsWindowAppearing())
            {
                ImGui::SetScrollHereY();
            }
        }

        if (m_autocomplete_suggestions.size() > 12)
        {
            ImGui::Separator();
            ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
            ImGui::Text("  +%d more (keep typing to filter)", (int)m_autocomplete_suggestions.size() - 12);
            ImGui::PopStyleColor();
        }

        ImGui::Separator();
        ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
        ImGui::Text("  Tab/Enter: accept  |  Esc: dismiss  |  \u2191\u2193: navigate");
        ImGui::PopStyleColor();
    }
    ImGui::End();

    ImGui::PopStyleColor(2);
    ImGui::PopStyleVar(3);
}

void template_editor::render()
{
    ImGui::Begin("Templates");

    render_controls();
    ImGui::Separator();

    const float panel_width = ImGui::GetContentRegionAvail().x;
    constexpr float left_panel_width = 200.0f;
    const float right_panel_width = panel_width - left_panel_width - 10;

    ImGui::BeginChild("TemplateList", ImVec2(left_panel_width, 0), true);
    render_template_list();
    ImGui::EndChild();

    ImGui::SameLine();

    ImGui::BeginChild("EditorPanel", ImVec2(right_panel_width, 0), false);
    render_editor();
    ImGui::EndChild();

    if (m_show_delete_confirmation)
    {
        ImGui::OpenPopup("Delete Template?");
        m_show_delete_confirmation = false;
    }

    clrsync::gui::widgets::delete_confirmation_dialog(
        "Delete Template?", m_control_state.name, "template", m_current_palette, [this]() {
            bool success = m_template_controller.remove_template(m_control_state.name);
            if (success)
            {
                new_template();
                refresh_templates();
            }
            else
            {
                m_validation.set("Failed to delete template");
            }
        });

    ImGui::End();
}

void template_editor::render_controls()
{
    if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
        ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyPressed(ImGuiKey_S))
    {
        save_template();
    }

    m_controls.render(m_control_state, m_callbacks, m_current_palette, m_validation);
}

void template_editor::render_editor()
{
    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4));

    if (!m_control_state.is_editing_existing)
    {
        ImVec4 success_color = clrsync::gui::widgets::palette_color(m_current_palette, "success", "accent");
        ImGui::PushStyleColor(ImGuiCol_Text, success_color);
        ImGui::Text("  New Template");
        ImGui::PopStyleColor();
    }
    else
    {
        ImGui::Text("  %s", m_control_state.name.c_str());
        auto trim_right = [](const std::string &s) -> std::string {
            size_t end = s.find_last_not_of("\r\n");
            return (end == std::string::npos) ? "" : s.substr(0, end + 1);
        };

        std::string current_content = trim_right(m_editor.GetText());
        std::string saved_content = trim_right(m_saved_content);

        m_has_unsaved_changes = (current_content != saved_content);
        if (m_has_unsaved_changes)
        {
            ImGui::SameLine();
            ImVec4 warning_color = clrsync::gui::widgets::palette_color(m_current_palette, "warning", "accent");
            ImGui::PushStyleColor(ImGuiCol_Text, warning_color);
            ImGui::Text("(unsaved)");
            ImGui::PopStyleColor();
        }
    }

    ImGui::PopStyleVar();
    ImGui::Separator();

    bool consume_keys = false;

    if (m_show_autocomplete && ImGui::IsKeyPressed(ImGuiKey_Escape, false))
    {
        m_show_autocomplete = false;
        m_autocomplete_dismissed = true;

        m_dismiss_position = m_editor.GetCursorPosition();

        std::string line = m_editor.GetCurrentLineText();
        m_dismiss_brace_pos = -1;
        for (int i = m_dismiss_position.mColumn - 1; i >= 0; --i)
        {
            if (i < (int)line.length() && line[i] == '{')
            {
                m_dismiss_brace_pos = i;
                break;
            }
        }

        consume_keys = true;
    }
    else if (m_show_autocomplete && !m_autocomplete_suggestions.empty())
    {
        int max_visible = std::min((int)m_autocomplete_suggestions.size(), 12);

        if (ImGui::IsKeyPressed(ImGuiKey_DownArrow, false))
        {
            m_autocomplete_selected = (m_autocomplete_selected + 1) % max_visible;
            consume_keys = true;
        }
        else if (ImGui::IsKeyPressed(ImGuiKey_UpArrow, false))
        {
            m_autocomplete_selected = (m_autocomplete_selected - 1 + max_visible) % max_visible;
            consume_keys = true;
        }
        else if (ImGui::IsKeyPressed(ImGuiKey_Tab, false) ||
                 ImGui::IsKeyPressed(ImGuiKey_Enter, false))
        {
            if (m_autocomplete_selected >= 0 && m_autocomplete_selected < (int)m_autocomplete_suggestions.size())
            {
                auto start = m_autocomplete_start_pos;
                auto cursor_pos = m_editor.GetCursorPosition();
                
                TextEditor::Coordinates end;
                if (m_autocomplete_end_brace_pos >= 0)
                {
                    end = TextEditor::Coordinates(cursor_pos.mLine, m_autocomplete_end_brace_pos);
                }
                else
                {
                    end = cursor_pos;
                }
                
                std::string insert_text = m_autocomplete_suggestions[m_autocomplete_selected];
                if (m_autocomplete_end_brace_pos < 0)
                {
                    insert_text += "}";
                }
                
                const char* old_clipboard = ImGui::GetClipboardText();
                std::string saved_clipboard = old_clipboard ? old_clipboard : "";
                
                ImGui::SetClipboardText(insert_text.c_str());
                
                m_editor.SetSelection(start, end);
                m_editor.Paste();
                
                ImGui::SetClipboardText(saved_clipboard.c_str());
                
                m_show_autocomplete = false;
                m_autocomplete_dismissed = false;
            }
            consume_keys = true;
        }
    }

    if (consume_keys)
    {
        m_editor.SetHandleKeyboardInputs(false);
    }

    ImVec2 editor_pos = ImGui::GetCursorScreenPos();

    m_editor.Render("##TemplateEditor", ImVec2(0, 0), true);

    if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && m_editor.HasSelection())
    {
        std::string selected_text = m_editor.GetSelectedText();
        
        if (!selected_text.empty())
        {
            bool starts_with_brace = selected_text.front() == '{';
            bool ends_with_brace = selected_text.back() == '}';
            
            if (starts_with_brace || ends_with_brace)
            {
                auto cursor = m_editor.GetCursorPosition();
                std::string line = m_editor.GetCurrentLineText();
                
                int brace_start = -1;
                int brace_end = -1;
                
                for (int i = cursor.mColumn - 1; i >= 0; --i)
                {
                    if (i < (int)line.length() && line[i] == '{')
                    {
                        brace_start = i;
                        break;
                    }
                }
                
                if (brace_start >= 0)
                {
                    for (int i = brace_start + 1; i < (int)line.length(); ++i)
                    {
                        if (line[i] == '}')
                        {
                            brace_end = i;
                            break;
                        }
                    }
                }
                
                if (brace_start >= 0 && brace_end > brace_start + 1)
                {
                    TextEditor::Coordinates sel_start(cursor.mLine, brace_start + 1);
                    TextEditor::Coordinates sel_end(cursor.mLine, brace_end);
                    m_editor.SetSelection(sel_start, sel_end);
                }
            }
        }
    }

    if (consume_keys)
    {
        m_editor.SetHandleKeyboardInputs(true);
    }

    update_autocomplete_suggestions();
    render_autocomplete(editor_pos);
}

void template_editor::render_template_list()
{
    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));

    ImGui::Text("Templates");
    ImGui::SameLine(ImGui::GetContentRegionAvail().x - 20);
    ImGui::TextDisabled("(%d)", (int)m_template_controller.templates().size());
    ImGui::Separator();

    if (!m_control_state.is_editing_existing)
    {
        ImVec4 success_color = clrsync::gui::widgets::palette_color(m_current_palette, "success", "accent");
        ImVec4 success_bg = ImVec4(success_color.x, success_color.y, success_color.z, 0.5f);
        ImGui::PushStyleColor(ImGuiCol_Text, success_color);
        ImGui::PushStyleColor(ImGuiCol_Header, success_bg);
        ImGui::Selectable("+ New Template", true);
        ImGui::PopStyleColor(2);
        ImGui::Separator();
    }

    const auto &templates = m_template_controller.templates();

    for (const auto &[key, tmpl] : templates)
    {
        const bool selected = (m_control_state.name == key && m_control_state.is_editing_existing);

        if (!tmpl.enabled())
        {
            ImVec4 disabled_color = clrsync::gui::widgets::palette_color(
                m_current_palette, "on_surface_variant", "editor_inactive");
            ImGui::PushStyleColor(ImGuiCol_Text, disabled_color);
        }

        if (ImGui::Selectable(key.c_str(), selected))
        {
            load_template(key);
        }

        if (!tmpl.enabled())
        {
            ImGui::PopStyleColor();
        }

        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("Template: %s", key.c_str());
            ImGui::Separator();
            ImGui::Text("Status: %s", tmpl.enabled() ? "Enabled" : "Disabled");
            if (!tmpl.output_path().empty())
                ImGui::Text("Output: %s", tmpl.output_path().c_str());
            ImGui::EndTooltip();
        }
    }

    ImGui::PopStyleVar();
}

bool template_editor::is_valid_path(const std::string &path)
{
    const std::string invalid_chars = "<>|\"";
    for (const char c : invalid_chars)
    {
        if (path.find(c) != std::string::npos)
        {
            return false;
        }
    }

    if (path.find_first_not_of(" \t\n\r./\\") == std::string::npos)
    {
        return false;
    }

    try
    {
        std::filesystem::path fs_path(path);

        const auto parent = fs_path.parent_path();

        if (parent.empty())
        {
            return false;
        }

        if (!parent.empty() && !std::filesystem::exists(parent))
        {
            if (parent.string().find_first_of("<>|\"") != std::string::npos)
            {
                return false;
            }
        }

        const auto filename = fs_path.filename().string();
        if (filename.empty() || filename == "." || filename == "..")
        {
            return false;
        }

        return true;
    }
    catch (...)
    {
        return false;
    }
}

void template_editor::save_template()
{
    std::string trimmed_name = m_control_state.name;
    trimmed_name.erase(0, trimmed_name.find_first_not_of(" \t\n\r"));
    trimmed_name.erase(trimmed_name.find_last_not_of(" \t\n\r") + 1);

    std::string trimmed_input_path = m_control_state.input_path;
    trimmed_input_path.erase(0, trimmed_input_path.find_first_not_of(" \t\n\r"));
    trimmed_input_path.erase(trimmed_input_path.find_last_not_of(" \t\n\r") + 1);

    std::string trimmed_path = m_control_state.output_path;
    trimmed_path.erase(0, trimmed_path.find_first_not_of(" \t\n\r"));
    trimmed_path.erase(trimmed_path.find_last_not_of(" \t\n\r") + 1);

    if (trimmed_name.empty())
    {
        m_validation.set("Error: Template name cannot be empty!");
        return;
    }

    if (trimmed_input_path.empty())
    {
        m_validation.set("Error: Input path cannot be empty!");
        return;
    }

    if (trimmed_path.empty())
    {
        m_validation.set("Error: Output path cannot be empty!");
        return;
    }

    if (!is_valid_path(trimmed_path))
    {
        m_validation.set("Error: Output path is invalid! Must be a valid file path with directory.");
        return;
    }

    m_validation.clear();

    auto &cfg = clrsync::core::config::instance();

    std::filesystem::path template_file = clrsync::core::normalize_path(trimmed_input_path);

    auto parent_dir = template_file.parent_path();
    if (!parent_dir.empty() && !std::filesystem::exists(parent_dir))
    {
        try
        {
            std::filesystem::create_directories(parent_dir);
        }
        catch (const std::exception &e)
        {
            m_validation.set("Error: Could not create directory for input path");
            return;
        }
    }

    std::string template_content = m_editor.GetText();

    std::ofstream out(template_file);
    if (!out.is_open())
    {
        m_validation.set("Failed to write template file");
        return;
    }

    out << template_content;
    out.close();

    clrsync::core::theme_template tmpl(trimmed_name, template_file.string(), trimmed_path);
    tmpl.set_reload_command(m_control_state.reload_command);
    tmpl.set_enabled(m_control_state.enabled);

    auto result = cfg.update_template(trimmed_name, tmpl);
    if (!result)
    {
        m_validation.set("Error saving template: " + result.error().description());
        return;
    }

    m_control_state.name = trimmed_name;
    m_control_state.input_path = trimmed_input_path;
    m_control_state.output_path = trimmed_path;
    m_control_state.is_editing_existing = true;
    m_saved_content = m_editor.GetText();
    m_has_unsaved_changes = false;

    refresh_templates();
}

void template_editor::load_template(const std::string &name)
{
    const auto &templates = m_template_controller.templates();
    auto it = templates.find(name);

    if (it != templates.end())
    {
        const auto &tmpl = it->second;
        m_control_state.name = name;
        m_control_state.input_path = tmpl.template_path();
        m_control_state.output_path = tmpl.output_path();
        m_control_state.reload_command = tmpl.reload_command();
        m_control_state.enabled = tmpl.enabled();
        m_control_state.is_editing_existing = true;
        m_validation.clear();

        std::ifstream in(tmpl.template_path());
        if (in.is_open())
        {
            std::string content;
            std::string line;
            while (std::getline(in, line))
            {
                content += line + "\n";
            }
            in.close();

            m_editor.SetText(content);
            m_saved_content = content;
            m_has_unsaved_changes = false;
        }
        else
        {
            m_validation.set("Error loading template: Failed to open file");
        }
    }
}

void template_editor::new_template()
{
    m_control_state.name = "new_template";
    std::string default_content =
        "# Enter your template here\n# Use {color_key} for color variables\n# "
        "Examples: {color.hex}, {color.rgb}, {color.r}\n\n";
    m_editor.SetText(default_content);
    m_saved_content = default_content;
    m_control_state.input_path = "";
    m_control_state.output_path = "";
    m_control_state.reload_command = "";
    m_control_state.enabled = true;
    m_control_state.is_editing_existing = false;
    m_validation.clear();
    m_has_unsaved_changes = false;
}

void template_editor::delete_template()
{
    if (!m_control_state.is_editing_existing || m_control_state.name.empty())
        return;

    m_show_delete_confirmation = true;
}

void template_editor::refresh_templates()
{
    m_template_controller.refresh();
}
