#include "lumacs/isearch_manager.hpp"
#include "lumacs/editor_core.hpp"
#include <spdlog/spdlog.h>

namespace lumacs {

ISearchManager::ISearchManager(EditorCore& core)
    : core_(core) {}

void ISearchManager::start(bool forward) {
    active_ = true;
    direction_forward_ = forward;
    failed_ = false;
    match_range_.reset();
    start_cursor_ = core_.cursor();
    last_query_.clear();
    spdlog::debug("ISearch started (direction: {})", forward ? "forward" : "backward");
}

void ISearchManager::stop(bool restore_cursor) {
    active_ = false;
    match_range_.reset();
    failed_ = false;

    if (restore_cursor && start_cursor_.has_value()) {
        core_.set_cursor(start_cursor_.value());
    }
    start_cursor_.reset();

    core_.set_message("");
    spdlog::debug("ISearch stopped");
}

void ISearchManager::update(const std::string& query) {
    if (query.empty()) {
        match_range_.reset();
        failed_ = false;
        core_.set_message(prompt_text_);
        return;
    }

    last_query_ = query;

    // Start search from current cursor
    Position search_start_pos = core_.cursor();

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

    if (match) {
        match_range_ = match;
        failed_ = false;
        core_.set_cursor(match->start);
        core_.set_message(prompt_text_ + " " + query);
    } else {
        match_range_.reset();
        failed_ = true;
        core_.set_message(prompt_text_ + " " + query + " (Failed)");
    }
}

void ISearchManager::next_match() {
    if (!active_ || !match_range_) return;

    Position search_start_pos;
    if (direction_forward_) {
        // Start search after current match
        search_start_pos = match_range_->end;
    } else {
        // Start search before current match
        search_start_pos = match_range_->start;
        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_query_.empty()) {
        if (direction_forward_) {
            match = core_.buffer().find(last_query_, search_start_pos);
            // If no match found after current, try wrapping to start of buffer
            if (!match) {
                match = core_.buffer().find(last_query_, {0, 0});
            }
        } else {
            match = core_.buffer().find_backward(last_query_, search_start_pos);
            // If no match found before current, try wrapping to end of buffer
            if (!match) {
                match = core_.buffer().find_backward(last_query_, {
                    core_.buffer().line_count() - 1,
                    core_.buffer().line(core_.buffer().line_count() - 1).size()
                });
            }
        }
    }

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

void ISearchManager::previous_match() {
    if (!active_ || !match_range_) {
        // If we have a query but no active match, search backward from current cursor
        if (!last_query_.empty()) {
            direction_forward_ = false;
            update(last_query_);
        }
        return;
    }

    Position search_start_pos = match_range_->start;
    if (search_start_pos.column > 0) {
        search_start_pos.column -= 1;
    } else if (search_start_pos.line > 0) {
        search_start_pos.line -= 1;
        search_start_pos.column = core_.buffer().line(search_start_pos.line).size();
    } else {
        // Wrap around to end of buffer
        search_start_pos = {
            core_.buffer().line_count() - 1,
            core_.buffer().line(core_.buffer().line_count() - 1).size()
        };
    }

    std::optional<Range> match;
    if (!last_query_.empty()) {
        match = core_.buffer().find_backward(last_query_, search_start_pos);
        if (!match) {
            // Wrap around
            match = core_.buffer().find_backward(last_query_, {
                core_.buffer().line_count() - 1,
                core_.buffer().line(core_.buffer().line_count() - 1).size()
            });
        }
    }

    if (match) {
        match_range_ = match;
        failed_ = false;
        core_.set_cursor(match->start);
        core_.set_message(prompt_text_ + " " + last_query_);
    } else {
        failed_ = true;
        core_.set_message(prompt_text_ + " " + last_query_ + " (No more matches backward)");
    }
}

} // namespace lumacs
