#include "lumacs/completion_system.hpp"
#include "lumacs/editor_core.hpp" // For accessing EditorCore for completion data
#include <algorithm> // For std::remove_if
#include <filesystem> // For file path completion

namespace lumacs {

// --- Concrete CompletionSource Implementations ---

/// @brief Completion source for editor commands.
class CommandCompletionSource : public ICompletionSource {
public:
    CommandCompletionSource(EditorCore& core) : core_(core) {}

    std::vector<CompletionCandidate> get_candidates(const std::string& input_text) override {
        std::vector<CompletionCandidate> candidates;
        std::vector<std::string> all_command_names = core_.command_system().get_command_names(); // Get actual command names
        
        for (const auto& cmd_name : all_command_names) {
            if (cmd_name.rfind(input_text, 0) == 0) { // Check if command starts with input_text
                std::string description = "";
                if (auto doc_opt = core_.command_system().get_command_doc_string(cmd_name)) {
                    description = *doc_opt;
                }
                candidates.emplace_back(cmd_name, 0, "", description); // Use actual description
            }
        }
        return candidates;
    }

private:
    EditorCore& core_;
};

/// @brief Completion source for buffer names.
class BufferNameCompletionSource : public ICompletionSource {
public:
    BufferNameCompletionSource(EditorCore& core) : core_(core) {}

    std::vector<CompletionCandidate> get_candidates(const std::string& input_text) override {
        std::vector<CompletionCandidate> candidates;
        std::vector<std::string> all_buffer_names = core_.get_buffer_names(); // Get actual buffer names
        for (const auto& name : all_buffer_names) {
            if (name.rfind(input_text, 0) == 0) {
                candidates.emplace_back(name);
            }
        }
        return candidates;
    }

private:
    EditorCore& core_;
};

/// @brief Completion source for file paths.
class FilePathCompletionSource : public ICompletionSource {
public:
    FilePathCompletionSource(EditorCore& core) : core_(core) {}

    std::vector<CompletionCandidate> get_candidates(const std::string& input_text) override {
        std::vector<CompletionCandidate> candidates;
        std::filesystem::path current_path = input_text;
        
        // If input ends with /, list contents of that directory
        if (input_text.empty() || input_text.back() == '/') {
            try {
                for (const auto& entry : std::filesystem::directory_iterator(current_path)) {
                    std::string path_str = entry.path().string();
                    if (entry.is_directory()) {
                        path_str += "/";
                    }
                    candidates.emplace_back(path_str);
                }
            } catch (const std::filesystem::filesystem_error& e) {
                // Ignore errors like "No such file or directory"
            }
        } else {
            // Find files/dirs that start with the input_text in the parent directory
            std::filesystem::path parent_path = current_path.parent_path();
            std::string stem = current_path.filename().string();
            
            try {
                for (const auto& entry : std::filesystem::directory_iterator(parent_path)) {
                    std::string entry_name = entry.path().filename().string();
                    if (entry_name.rfind(stem, 0) == 0) {
                        std::string full_path = entry.path().string();
                        if (entry.is_directory()) {
                            full_path += "/";
                        }
                        candidates.emplace_back(full_path);
                    }
                }
            } catch (const std::filesystem::filesystem_error& e) {
                // Ignore errors
            }
        }
        return candidates;
    }

private:
    [[maybe_unused]] EditorCore& core_; // Reserved for future filesystem operations
};

/// @brief Completion source for theme names.
class ThemeNameCompletionSource : public ICompletionSource {
public:
    ThemeNameCompletionSource(EditorCore& core) : core_(core) {}

    std::vector<CompletionCandidate> get_candidates(const std::string& input_text) override {
        std::vector<CompletionCandidate> candidates;
        std::vector<std::string> all_theme_names = core_.theme_manager().theme_names();
        for (const auto& name : all_theme_names) {
            if (name.rfind(input_text, 0) == 0) {
                candidates.emplace_back(name);
            }
        }
        return candidates;
    }

private:
    [[maybe_unused]] EditorCore& core_; // Reserved for future filesystem operations
};


// --- CompletionSystem Implementation ---

CompletionSystem::CompletionSystem(EditorCore& core) : core_(core) {
    // Register default completion sources
    register_source(MinibufferMode::Command, std::make_unique<CommandCompletionSource>(core));
    register_source(MinibufferMode::BufferName, std::make_unique<BufferNameCompletionSource>(core));
    register_source(MinibufferMode::FilePath, std::make_unique<FilePathCompletionSource>(core));
    register_source(MinibufferMode::ThemeName, std::make_unique<ThemeNameCompletionSource>(core));
}

void CompletionSystem::register_source(MinibufferMode mode, std::unique_ptr<ICompletionSource> source) {
    sources_[mode] = std::move(source);
}

std::vector<CompletionCandidate> CompletionSystem::get_candidates_for_mode(MinibufferMode mode, const std::string& input_text) {
    auto it = sources_.find(mode);
    if (it != sources_.end()) {
        return it->second->get_candidates(input_text);
    }
    return {}; // No completion source registered for this mode
}

} // namespace lumacs
