#include "lumacs/minibuffer_manager.hpp"
#include "lumacs/editor_core.hpp" // For EditorCore interaction
#include "lumacs/lua_api.hpp"     // For LuaApi interaction
#include "lumacs/minibuffer_mode_hash.hpp" // New include for MinibufferMode hash
#include "lumacs/completion_system.hpp" // Include for CompletionSystem
#include "lumacs/command_system.hpp" // For Command and CommandSystem
#include <functional> // Required for std::function
#include <sstream>    // For parsing command line

#include <iostream> // TODO: Replace with proper logging

namespace lumacs {

MinibufferManager::MinibufferManager(EditorCore& core, LuaApi& lua_api, CompletionSystem& completion_system)
    : core_(core), lua_api_(lua_api), completion_system_(completion_system) {
    // Initialize history managers for each mode
    histories_[MinibufferMode::Command] = HistoryManager();
    histories_[MinibufferMode::FilePath] = HistoryManager();
    histories_[MinibufferMode::BufferName] = HistoryManager();
    histories_[MinibufferMode::ThemeName] = HistoryManager();
    histories_[MinibufferMode::ISearch] = HistoryManager();
    histories_[MinibufferMode::ystring] = HistoryManager();
    histories_[MinibufferMode::y_or_n_p] = HistoryManager();
}

void MinibufferManager::activate_minibuffer(MinibufferMode mode, const std::string& prompt,
                                             std::function<void(const std::string&)> on_submit,
                                             std::function<void()> on_cancel) {
    current_mode_ = mode;
    prompt_text_ = prompt;
    input_buffer_ = ""; // Clear previous input
    on_submit_callback_ = on_submit;
    on_cancel_callback_ = on_cancel;
    cursor_position_ = 0; // Initialize cursor position
    
    // Set current history manager based on mode
    current_history_ = &histories_[mode];

    // Initialize ISearch state
    isearch_active_ = (mode == MinibufferMode::ISearch);
    isearch_match_range_.reset();
    isearch_failed_ = false;
    if (mode == MinibufferMode::ISearch) {
        isearch_start_cursor_ = core_.cursor(); // Save cursor position when ISearch starts
        isearch_direction_forward_ = true; // Default to forward search
    } else {
        isearch_start_cursor_.reset();
    }
    last_search_query_.clear();

    update_completion_candidates(); 
}

void MinibufferManager::deactivate_minibuffer() {
    current_mode_ = MinibufferMode::None;
    prompt_text_ = "";
    input_buffer_ = "";
    on_submit_callback_ = nullptr;
    on_cancel_callback_ = nullptr;
    current_history_ = nullptr; // Clear current history pointer
    completion_candidates_.clear();
    completion_index_ = 0;
    cursor_position_ = 0; // Reset cursor position

    // Clear ISearch state
    isearch_active_ = false;
    isearch_match_range_.reset();
    isearch_failed_ = false;
    isearch_start_cursor_.reset();
    last_search_query_.clear();
}

bool MinibufferManager::handle_key_event(const std::string& key_name) {
    if (current_mode_ == MinibufferMode::None) {
        return false; // Minibuffer not active
    }

    if (current_mode_ == MinibufferMode::ISearch) {
        if (key_name == "Return") {
            stop_isearch(); // Deactivate ISearch, cursor stays at match
            deactivate_minibuffer(); // End minibuffer session
            return true;
        } else if (key_name == "Escape") {
            stop_isearch(); // Restores cursor, clears state
            deactivate_minibuffer(); // End minibuffer session
            return true;
        } else if (key_name == "C-s") {
            // Next match (forward)
            isearch_direction_forward_ = true;
            next_isearch_match();
            return true;
        } else if (key_name == "C-r") {
            // Previous match (backward)
            isearch_direction_forward_ = false;
            previous_isearch_match();
            return true;
        } else if (key_name == "BackSpace") {
            if (cursor_position_ > 0) {
                input_buffer_.erase(cursor_position_ - 1, 1);
                cursor_position_--;
                update_isearch(input_buffer_); // Update search with new query
            } else {
                // If query is empty, cancel ISearch.
                stop_isearch();
                deactivate_minibuffer();
            }
            return true;
        } else if (key_name.length() == 1) { // Regular character input
            input_buffer_.insert(cursor_position_, key_name);
            cursor_position_++;
            update_isearch(input_buffer_); // Update search with new query
            return true;
        }
        // If other keys are pressed in ISearch mode, they are usually treated as part of the query.
        // For now, if not specifically handled, ignore them.
        return false;
    }

    // --- Generic Minibuffer Handling (for other modes) ---
    if (key_name == "Return") {
        add_to_history();
        if (on_submit_callback_) {
            on_submit_callback_(input_buffer_);
        }
        deactivate_minibuffer();
        return true;
    } else if (key_name == "Escape") {
        if (on_cancel_callback_) {
            on_cancel_callback_();
        }
        deactivate_minibuffer();
        return true;
    } else if (key_name == "BackSpace") {
        if (cursor_position_ > 0) {
            input_buffer_.erase(cursor_position_ - 1, 1);
            cursor_position_--;
            update_completion_candidates(); // Update completions on backspace
        }
        return true;
    } else if (key_name == "Delete") {
        if (cursor_position_ < input_buffer_.length()) {
            input_buffer_.erase(cursor_position_, 1);
            update_completion_candidates(); // Update completions on delete
        }
        return true;
    } else if (key_name == "Left" || key_name == "ArrowLeft") {
        if (cursor_position_ > 0) {
            cursor_position_--;
        }
        return true;
    } else if (key_name == "Right" || key_name == "ArrowRight") {
        if (cursor_position_ < input_buffer_.length()) {
            cursor_position_++;
        }
        return true;
    } else if (key_name == "Home") {
        cursor_position_ = 0;
        return true;
    } else if (key_name == "End") {
        cursor_position_ = input_buffer_.length();
        return true;
    } else if (key_name == "Tab") {
        complete();
        return true;
    } else if (key_name == "C-p" || key_name == "ArrowUp") { // Previous history
        history_previous();
        return true;
    } else if (key_name == "C-n" || key_name == "ArrowDown") { // Next history
        history_next();
        return true;
    } else if (key_name.length() == 1) { // Regular character input
        input_buffer_.insert(cursor_position_, key_name);
        cursor_position_++;
        update_completion_candidates(); // Update completions on new input
        return true;
    }
    return false; 
}

std::string MinibufferManager::get_prompt() const {
    return prompt_text_;
}

std::string MinibufferManager::get_input_buffer() const {
    return input_buffer_;
}

size_t MinibufferManager::get_cursor_position() const {
    return cursor_position_;
}

void MinibufferManager::set_input_buffer(const std::string& input) {
    input_buffer_ = input;
    cursor_position_ = input_buffer_.length();
    update_completion_candidates();
}

void MinibufferManager::add_to_history() {
    if (current_history_) {
        current_history_->add_item(input_buffer_);
    }
}

void MinibufferManager::history_previous() {
    if (current_history_) {
        input_buffer_ = current_history_->previous();
        cursor_position_ = input_buffer_.length(); // Move cursor to end of history item
        update_completion_candidates();
    }
}

void MinibufferManager::history_next() {
    if (current_history_) {
        input_buffer_ = current_history_->next();
        cursor_position_ = input_buffer_.length(); // Move cursor to end of history item
        update_completion_candidates();
    }
}

void MinibufferManager::update_completion_candidates() {
    completion_candidates_.clear();
    completion_index_ = 0;

    if (input_buffer_.empty()) {
        return;
    }

    completion_candidates_ = completion_system_.get_candidates_for_mode(current_mode_, input_buffer_);
}

std::vector<CompletionCandidate> MinibufferManager::get_completion_candidates() const {
    return completion_candidates_;
}

std::optional<std::string> MinibufferManager::get_current_completion() const {
    if (!completion_candidates_.empty()) {
        return completion_candidates_[completion_index_].text;
    }
    return std::nullopt;
}

void MinibufferManager::complete() {
    if (!completion_candidates_.empty()) {
        input_buffer_ = completion_candidates_[completion_index_].text;
        completion_index_ = (completion_index_ + 1) % completion_candidates_.size();
        // If we cycle, reset the index so next tab starts from the top.
        // Or, more Emacs-like, cycle through the list and if we get back to original,
        // stay there until new input. For now, simple cycle.
    }
}

CommandResult MinibufferManager::parse_and_execute_command_string(const std::string& command_line) {
    std::string command_name;
    std::vector<std::string> args;
    std::stringstream ss(command_line);
    
    ss >> command_name; // Extract command name

    std::string arg;
    while (ss >> arg) { // Extract arguments
        args.push_back(arg);
    }

    // Directly execute the command. If the command is interactive and needs more arguments,
    // the execute method will return PendingInput. This assumes the caller (e.g., Lua API)
    // will know how to handle CommandStatus::PendingInput if it tries to execute an
    // interactive command that requires more input than provided in the string.
    // However, for typical Lua API calls, commands are expected to be fully specified.
    return core_.command_system().execute(command_name, args);
}

// === ISearch Implementations ===

void MinibufferManager::start_isearch(bool forward) {
    if (current_mode_ != MinibufferMode::ISearch) {
        // This should be called only when ISearch mode is active
        return;
    }
    isearch_direction_forward_ = forward;
    // Initial search is triggered by `update_isearch` through `handle_key_event`
}

void MinibufferManager::update_isearch(const std::string& query) {
    if (query.empty()) {
        isearch_match_range_.reset();
        isearch_failed_ = false;
        core_.set_message(prompt_text_); // Reset prompt
        return;
    }

    last_search_query_ = query; // Store last successful query

    // Start search from current cursor, or from start_cursor_ if first search
    Position search_start_pos = core_.cursor();

    // Perform search
    std::optional<Range> match;
    if (isearch_direction_forward_) {
        match = core_.buffer().find(query, search_start_pos);
    } else {
        match = core_.buffer().find_backward(query, search_start_pos);
    }

    if (match) {
        isearch_match_range_ = match;
        isearch_failed_ = false;
        core_.set_cursor(match->start); // Move cursor to start of match
        core_.set_message(prompt_text_ + " " + query); // Update message with query
    } else {
        isearch_match_range_.reset();
        isearch_failed_ = true;
        core_.set_message(prompt_text_ + " " + query + " (Failed)"); // Indicate failure
    }
}

void MinibufferManager::next_isearch_match() {
    if (!isearch_active_ || !isearch_match_range_) return;

    Position search_start_pos;
    if (isearch_direction_forward_) {
        // Start search after current match
        search_start_pos = isearch_match_range_->end;
    } else {
        // Start search before current match (need to go back two steps for previous match of same size)
        search_start_pos = isearch_match_range_->start;
        // If current match is at 0,0 and we search backward, we need to wrap around.
        // For simplicity, let's just search from start of buffer for now if at start of buffer.
        if (search_start_pos.column == 0 && search_start_pos.line == 0) {
            // Wrap around to end of buffer
            search_start_pos = {core_.buffer().line_count() - 1, core_.buffer().line(core_.buffer().line_count() - 1).size()};
        } else if (search_start_pos.column > 0) {
            search_start_pos.column -=1;
        } else {
            search_start_pos.line -=1;
            search_start_pos.column = core_.buffer().line(search_start_pos.line).size();
        }
    }
    
    std::optional<Range> match;
    if (!last_search_query_.empty()) {
        if (isearch_direction_forward_) {
            match = core_.buffer().find(last_search_query_, search_start_pos);
            // If no match found after current, try wrapping to start of buffer
            if (!match) {
                match = core_.buffer().find(last_search_query_, {0,0});
            }
        } else {
            match = core_.buffer().find_backward(last_search_query_, search_start_pos);
            // If no match found before current, try wrapping to end of buffer
            if (!match) {
                match = core_.buffer().find_backward(last_search_query_, {core_.buffer().line_count() - 1, core_.buffer().line(core_.buffer().line_count() - 1).size()});
            }
        }
    }

    if (match) {
        isearch_match_range_ = match;
        isearch_failed_ = false;
        core_.set_cursor(match->start);
        core_.set_message(prompt_text_ + " " + last_search_query_);
    } else {
        isearch_failed_ = true;
        core_.set_message(prompt_text_ + " " + last_search_query_ + " (No more matches)");
    }
}

void MinibufferManager::previous_isearch_match() {
    // Simply reverse direction and call next_isearch_match
    // For now, next_isearch_match handles both, but needs to be smarter about wrap-around.
    // This is essentially "next in reverse direction".
    // For now, let's make it simple for initial implementation.
    // If the direction is forward, it means we were searching forward. "Previous" means search backward.
    // If the direction is backward, "Previous" means search forward.
    // This is often complex in Emacs. Let's just toggle the direction and re-search from the current match start.
    
    if (!isearch_active_ || !isearch_match_range_) {
        // If we have a query but no active match, search backward from current cursor
        if (!last_search_query_.empty()) {
            isearch_direction_forward_ = false;
            update_isearch(last_search_query_);
        }
        return;
    }
    
    Position search_start_pos = isearch_match_range_->start;
    if (search_start_pos.column > 0) {
        search_start_pos.column -=1;
    } else {
        search_start_pos.line -=1;
        if (search_start_pos.line < 0) { // Wrap around
            search_start_pos = {core_.buffer().line_count() - 1, core_.buffer().line(core_.buffer().line_count() - 1).size()};
        } else {
            search_start_pos.column = core_.buffer().line(search_start_pos.line).size();
        }
    }

    std::optional<Range> match;
    if (!last_search_query_.empty()) {
        match = core_.buffer().find_backward(last_search_query_, search_start_pos);
        if (!match) { // Wrap around
            match = core_.buffer().find_backward(last_search_query_, {core_.buffer().line_count() - 1, core_.buffer().line(core_.buffer().line_count() - 1).size()});
        }
    }
    
    if (match) {
        isearch_match_range_ = match;
        isearch_failed_ = false;
        core_.set_cursor(match->start);
        core_.set_message(prompt_text_ + " " + last_search_query_);
    } else {
        isearch_failed_ = true;
        core_.set_message(prompt_text_ + " " + last_search_query_ + " (No more matches backward)");
    }
}

void MinibufferManager::stop_isearch() {
    isearch_active_ = false;
    isearch_match_range_.reset();
    isearch_failed_ = false;
    last_search_query_.clear();
    // Do NOT deactivate minibuffer; ISearch needs to go into a normal minibuffer state usually.
    // The caller of stop_isearch (e.g., handle_key_event) should handle deactivation or other transitions.
    core_.set_message(""); // Clear message
    // Restore cursor if it was moved by isearch
    if (isearch_start_cursor_.has_value()) {
        core_.set_cursor(isearch_start_cursor_.value());
        isearch_start_cursor_.reset();
    }
}

} // namespace lumacs