// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3

#pragma once

#include "../layout.h"
#include "../../daemon/embedded_daemon.h"
#include "../../daemon/xmrig_manager.h"
#include "../../rpc/rpc_client.h"
#include "../../rpc/rpc_worker.h"

#include <string>
#include <vector>
#include <deque>
#include <mutex>

namespace dragonx {
namespace ui {

/**
 * @brief Console tab for daemon output and command input
 * 
 * Shows dragonxd output and allows executing RPC commands.
 */
class ConsoleTab {
public:
    ConsoleTab();
    ~ConsoleTab();
    
    /**
     * @brief Render the console tab
     * @param daemon Pointer to embedded daemon (may be null)
     * @param rpc Pointer to RPC client for command execution
     * @param xmrig Pointer to xmrig manager for pool mining output (may be null)
     */
    void render(daemon::EmbeddedDaemon* daemon, rpc::RPCClient* rpc, rpc::RPCWorker* worker, daemon::XmrigManager* xmrig = nullptr);

    /**
     * @brief Render the RPC Command Reference popup at top-level scope.
     * Must be called outside any child window so the modal blocks all input.
     */
    void renderCommandsPopupModal();
    
    /**
     * @brief Add a line to the console output
     */
    void addLine(const std::string& line, ImU32 color = IM_COL32(200, 200, 200, 255));
    void addRpcTraceLine(const std::string& source, const std::string& method);
    
    /**
     * @brief Clear console output
     */
    void clear();
    
    /**
     * @brief Check if auto-scroll is enabled
     */
    bool isAutoScrollEnabled() const { return auto_scroll_; }

    // Scanline effect toggle (set from settings)
    static bool s_scanline_enabled;

    // Console output zoom factor (1.0 = default caption font size)
    static float s_console_zoom;

    // Show/hide daemon output messages
    static bool s_daemon_messages_enabled;

    // Show only error messages (filter toggle)
    static bool s_errors_only_enabled;

    // Show app RPC calls made through RPCClient (method/source only)
    static bool s_rpc_trace_enabled;

    /// Refresh console text colors for current theme (call after theme switch)
    static void refreshColors();
    
    // Colors — follow active theme (public for use by notification forwarding)
    static ImU32 COLOR_COMMAND;
    static ImU32 COLOR_RESULT;
    static ImU32 COLOR_ERROR;
    static ImU32 COLOR_DAEMON;
    static ImU32 COLOR_INFO;
    static ImU32 COLOR_RPC;
    
private:
    struct ConsoleLine {
        std::string text;
        ImU32 color;
    };
    
    void executeCommand(const std::string& cmd, rpc::RPCClient* rpc, rpc::RPCWorker* worker);
    void addCommandResult(const std::string& cmd, const std::string& result, bool is_error = false);
    void renderToolbar(daemon::EmbeddedDaemon* daemon);
    void renderOutput();
    void renderInput(rpc::RPCClient* rpc, rpc::RPCWorker* worker);
    void renderCommandsPopup();
    
    // Selection helpers
    void handleSelection();
    std::string getSelectedText() const;
    void clearSelection();
    
    // Convert screen position to line/column
    struct TextPos {
        int line = -1;
        int col = 0;
    };
    TextPos screenToTextPos(ImVec2 screen_pos, float line_height) const;
    bool isPosBeforeOrEqual(const TextPos& a, const TextPos& b) const;
    TextPos selectionStart() const;  // Returns the earlier of sel_anchor_ and sel_end_
    TextPos selectionEnd() const;    // Returns the later of sel_anchor_ and sel_end_
    
    std::deque<ConsoleLine> lines_;
    std::vector<std::string> command_history_;
    int history_index_ = -1;
    char input_buffer_[4096] = {0};
    bool auto_scroll_ = true;
    bool scroll_to_bottom_ = false;
    float scroll_up_cooldown_ = 0.0f;    // seconds to wait before re-enabling auto-scroll
    int  new_lines_since_scroll_ = 0;     // new lines while scrolled up (for indicator)
    size_t last_daemon_output_size_ = 0;
    size_t last_xmrig_output_size_ = 0;
    bool shown_startup_message_ = false;
    daemon::EmbeddedDaemon::State last_daemon_state_ = daemon::EmbeddedDaemon::State::Stopped;
    bool last_rpc_connected_ = false;
    
    // Text selection state
    bool is_selecting_ = false;
    bool has_selection_ = false;
    TextPos sel_anchor_;  // Where the mouse was first pressed
    TextPos sel_end_;     // Where the mouse currently is / was released
    float output_scroll_y_ = 0.0f;    // Track scroll position for selection
    ImVec2 output_origin_ = {0, 0};   // Top-left of output area
    float output_line_height_ = 0.0f; // Text line height (for scanline alignment)

    struct ScanlineRow {
        float yTop = 0.0f;
        float yBot = 0.0f;
        int rowIndex = 0;
    };
    std::vector<ScanlineRow> scanline_rows_;
    
    std::mutex lines_mutex_;
    
    // Output filter
    char filter_text_[128] = {0};
    mutable std::vector<int> visible_indices_;  // Cached for selection mapping
    
    // Wrapped line height caching (for variable-height text wrapping)
    mutable std::vector<float> wrapped_heights_;      // Height of each visible line (accounts for wrapping)
    mutable std::vector<float> cumulative_y_offsets_; // Cumulative Y offset for each visible line
    mutable float total_wrapped_height_ = 0.0f;       // Total height of all visible lines
    mutable float cached_wrap_width_ = 0.0f;          // Wrap width used for cached heights
    
    // Sub-row layout: each visible line is split into wrap segments so
    // selection and hit-testing know the exact screen position of every
    // character.
    struct WrapSegment {
        int   byteStart;   // byte offset into ConsoleLine::text
        int   byteEnd;     // byte offset past last char in this segment
        float yOffset;     // Y offset of this segment relative to the line's top
        float height;      // visual height of this segment
    };
    mutable std::vector<std::vector<WrapSegment>> visible_wrap_segments_; // [vi] -> segments
    
    // Commands popup
    bool show_commands_popup_ = false;
};

} // namespace ui
} // namespace dragonx
