#pragma once

#include "lumacs/buffer.hpp"
#include "lumacs/window.hpp"
#include "lumacs/theme.hpp"
#include "lumacs/config.hpp"
#include "lumacs/keybinding.hpp"
#include "lumacs/modeline.hpp"
#include "lumacs/minibuffer_manager.hpp"
#include "lumacs/completion_system.hpp"
#include "lumacs/ui_interface.hpp"
#include "lumacs/i_command_target.hpp"
#include "lumacs/plugin_manager.hpp"
#include "lumacs/buffer_manager.hpp"
#include "lumacs/window_manager.hpp"
#include "lumacs/kill_ring_manager.hpp"
#include "lumacs/register_manager.hpp"
#include "lumacs/macro_manager.hpp"
#include "lumacs/rectangle_manager.hpp"
#include "lumacs/layout_node.hpp"
#include "lumacs/i_editor_notifier.hpp"
#include "lumacs/i_window_manager.hpp"
#include <memory>
#include <functional>

namespace lumacs {

class LuaApi;
class CommandSystem;
class PluginManager;

class EditorCore : public ICommandTarget, public IEditorNotifier, public IWindowManager {
public:
    EditorCore();
    ~EditorCore();

    EditorCore(const EditorCore&) = delete;
    EditorCore& operator=(const EditorCore&) = delete;
    EditorCore(EditorCore&&) noexcept = default;
    EditorCore& operator=(EditorCore&&) noexcept = default;

    // === ICommandTarget Implementation ===
    // Buffer Management (Delegated to BufferManager)
    [[nodiscard]] const Buffer& buffer() const noexcept override { return *buffer_manager_->active_buffer(); }
    [[nodiscard]] Buffer& buffer() noexcept override { return *buffer_manager_->active_buffer(); }
    bool load_file(const std::filesystem::path& path) override { return buffer_manager_->load_file(path); }
    void new_buffer(std::string name = "*scratch*") override { buffer_manager_->new_buffer(std::move(name)); }
    [[nodiscard]] std::vector<std::string> get_buffer_names() const override { return buffer_manager_->get_buffer_names(); }
    [[nodiscard]] std::shared_ptr<Buffer> get_buffer_by_name(const std::string& name) override { return buffer_manager_->get_buffer_by_name(name); }
    bool switch_buffer_in_window(const std::string& name) override { return buffer_manager_->switch_buffer_in_window(name); }
    bool close_buffer(const std::string& name) override { return buffer_manager_->close_buffer(name); }
    
    // Window Management (Delegated to WindowManager)
    [[nodiscard]] std::shared_ptr<Window> active_window() const override { return window_manager_->active_window(); }
    bool set_active_window(std::shared_ptr<Window> window) override { return window_manager_->set_active_window(window); }
    void split_horizontally() override { window_manager_->split_horizontally(); }
    void split_vertically() override { window_manager_->split_vertically(); }
    void close_active_window() override { window_manager_->close_active_window(); }
    void next_window() override { window_manager_->next_window(); } 
    
    // IWindowManager implementation (helpers)
    void collect_windows(LayoutNode* node, std::vector<std::shared_ptr<Window>>& windows) override;
    std::shared_ptr<LayoutNode> root_layout() const override { return window_manager_->root_layout(); }
    [[nodiscard]] Position cursor() const noexcept override;
    void set_cursor(Position pos) override;

    // Basic Editing
    void move_up() override;
    void move_down() override;
    void move_left() override;
    void move_right() override;
    void move_to_line_start() override;
    void move_to_line_end() override;
    void move_forward_word() override;
    void move_backward_word() override;
    void page_up() override;
    void page_down() override;
    void goto_beginning() override;
    void goto_end() override;
    void goto_line(size_t line) override;

    // Kill Ring (Delegated to KillRingManager)
    void kill_line() override;
    void kill_region() override;
    void copy_region_as_kill() override;
    void yank() override;
    void yank_pop() override;
    void kill_word() override;
    void backward_kill_word() override;

    // Message Display
    void set_message(std::string msg) override;

    // Quit
    void request_quit() override;

    // Configuration
    Config& config() override { return config_; }
    const Config& config() const override { return config_; }

    // Theme Management
    ThemeManager& theme_manager() override { return theme_manager_; }
    const ThemeManager& theme_manager() const override { return theme_manager_; }

    // Registers (Delegated to RegisterManager)
    void copy_to_register(char register_name, const std::string& text) override;
    bool insert_register(char register_name) override;
    void copy_region_to_register(char register_name) override;
    bool yank_from_register(char register_name) override;

    // Keyboard Macros (Delegated to MacroManager)
    void start_kbd_macro() override;
    void end_kbd_macro_or_call() override;
    void record_key_sequence(const std::string& key_sequence) override;
    [[nodiscard]] bool is_recording_macro() const noexcept override;

    // Rectangles (Delegated to RectangleManager)
    void kill_rectangle() override;
    void yank_rectangle() override;
    void string_rectangle(const std::string& text) override;

    // === Original EditorCore methods not part of ICommandTarget ===

    const std::string& last_message() const { return last_message_; }
    void check_and_clear_message(); 

    void enter_command_mode();
    void enter_buffer_switch_mode();
    void enter_kill_buffer_mode();
    void enter_find_file_mode();
    void enter_theme_selection_mode();
    void enter_isearch_mode();
    void enter_isearch_backward_mode();

    [[nodiscard]] std::vector<BufferManager::BufferInfo> get_all_buffer_info() const { return buffer_manager_->get_all_buffer_info(); }
    
    const Viewport& viewport() const noexcept;
    void set_viewport_size(int width, int height);
    void adjust_scroll();
    std::pair<size_t, size_t> visible_line_range() const;

    using EventCallback = std::function<void(EditorEvent)>;
    void on_event(EventCallback callback) { event_callbacks_.push_back(std::move(callback)); }
    void clear_event_callbacks() { event_callbacks_.clear(); }

    bool undo();
    bool redo();
    bool can_undo() const;
    bool can_redo() const;

    [[nodiscard]] KillRingManager& kill_ring_manager() noexcept { return *kill_ring_manager_; }
    [[nodiscard]] const KillRingManager& kill_ring_manager() const noexcept { return *kill_ring_manager_; }
    [[nodiscard]] RegisterManager& register_manager() noexcept { return *register_manager_; }
    [[nodiscard]] const RegisterManager& register_manager() const noexcept { return *register_manager_; }
    [[nodiscard]] MacroManager& macro_manager() noexcept { return *macro_manager_; }
    [[nodiscard]] const MacroManager& macro_manager() const noexcept { return *macro_manager_; }
    [[nodiscard]] RectangleManager& rectangle_manager() noexcept { return *rectangle_manager_; }
    [[nodiscard]] const RectangleManager& rectangle_manager() const noexcept { return *rectangle_manager_; }
    [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return *keybinding_manager_; }
    [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return *keybinding_manager_; }
    [[nodiscard]] LuaApi* lua_api() const { return lua_api_.get(); }
    [[nodiscard]] CommandSystem& command_system() noexcept { return *command_system_; }
    [[nodiscard]] const CommandSystem& command_system() const noexcept { return *command_system_; }
    [[nodiscard]] CompletionSystem& completion_system() noexcept { return *completion_system_; }
    [[nodiscard]] const CompletionSystem& completion_system() const noexcept { return *completion_system_; }
    [[nodiscard]] ModelineManager& modeline_manager() noexcept { return modeline_manager_member_; }
    [[nodiscard]] const ModelineManager& modeline_manager() const noexcept { return modeline_manager_member_; }
    [[nodiscard]] MinibufferManager& minibuffer_manager() noexcept { return *minibuffer_manager_; }
    [[nodiscard]] const MinibufferManager& minibuffer_manager() const noexcept { return *minibuffer_manager_; }
    [[nodiscard]] PluginManager& plugin_manager() noexcept { return *plugin_manager_; }
    [[nodiscard]] const PluginManager& plugin_manager() const noexcept { return *plugin_manager_; }
    [[nodiscard]] BufferManager& buffer_manager() noexcept { return *buffer_manager_; }
    [[nodiscard]] const BufferManager& buffer_manager() const noexcept { return *buffer_manager_; }
    [[nodiscard]] WindowManager& window_manager() noexcept { return *window_manager_; }
    [[nodiscard]] const WindowManager& window_manager() const noexcept { return *window_manager_; }

    void emit_event(EditorEvent event) override;

private:
    Position calculate_forward_word_pos(Position start_pos);
    Position calculate_backward_word_pos(Position start_pos);

    std::string last_message_;
    std::optional<std::chrono::steady_clock::time_point> message_clear_time_;
    std::vector<EventCallback> event_callbacks_;
    std::optional<Position> last_yank_start_;
    std::optional<Position> last_yank_end_;

    // Subsystems - Order matters for initialization based on dependencies
    // Declared in dependency order
    ThemeManager theme_manager_; // No dependencies
    Config config_; // No dependencies
    ModelineManager modeline_manager_member_; // Direct member, declared here
    std::unique_ptr<LuaApi> lua_api_; // Depends on nothing
    std::unique_ptr<CompletionSystem> completion_system_; // Depends on EditorCore (this)
    std::unique_ptr<MinibufferManager> minibuffer_manager_; // Depends on EditorCore, LuaApi, CompletionSystem
    std::unique_ptr<CommandSystem> command_system_; // Depends on EditorCore, MinibufferManager
    std::unique_ptr<KeyBindingManager> keybinding_manager_; // Depends on CommandSystem
    std::unique_ptr<PluginManager> plugin_manager_; // Depends on EditorCore, LuaApi
    std::unique_ptr<BufferManager> buffer_manager_; // Depends on EditorCore
    std::unique_ptr<WindowManager> window_manager_; // Depends on EditorCore, BufferManager
    std::unique_ptr<KillRingManager> kill_ring_manager_; // No dependencies
    std::unique_ptr<RegisterManager> register_manager_; // No dependencies
    std::unique_ptr<MacroManager> macro_manager_; // Depends on EditorCore
    std::unique_ptr<RectangleManager> rectangle_manager_; // Depends on EditorCore
};

} // namespace lumacs
