#pragma once

#include "core/events/EventBus.h"
#include "core/symbol/IGroupLinked.h"
#include "core/symbol/SymbolGroup.h"
#include "core/symbol/SymbolRef.h"
#include "screens/common/IStatefulScreen.h"
#include "services/llm/LlmService.h"

#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QListWidget>
#include <QMutex>
#include <QPlainTextEdit>
#include <QPointer>
#include <QPropertyAnimation>
#include <QPushButton>
#include <QScrollArea>
#include <QTimer>
#include <QVBoxLayout>
#include <QWidget>

#include <vector>

namespace fincept::screens {

class AiChatScreen : public QWidget, public IStatefulScreen, public fincept::IGroupLinked {
    Q_OBJECT
    Q_INTERFACES(fincept::IGroupLinked)
  public:
    explicit AiChatScreen(QWidget* parent = nullptr);

    void restore_state(const QVariantMap& state) override;
    QVariantMap save_state() const override;
    QString state_key() const override { return "ai_chat"; }
    // v2 adds: draft text, search text, scroll position, attached file path.
    // v3 adds: sidebar_collapsed.
    int state_version() const override { return 3; }

    // IGroupLinked — Phase 7: AI Chat is a consumer-only participant. When a
    // panel in the same group selects a symbol, the chat input gets a
    // gentle "Context: <SYMBOL>" prefix appended (visible to the user) so
    // their next prompt has the security in scope. Chat itself never
    // publishes — the symbol leaving here would not match any meaningful
    // user intent (the user typed a question, not a ticker selection).
    void set_group(fincept::SymbolGroup g) override;
    fincept::SymbolGroup group() const override { return link_group_; }
    void on_group_symbol_changed(const fincept::SymbolRef& ref) override;
    fincept::SymbolRef current_symbol() const override { return linked_symbol_; }

  protected:
    void showEvent(QShowEvent* e) override;
    void hideEvent(QHideEvent* e) override;
    bool eventFilter(QObject* obj, QEvent* event) override;
    void resizeEvent(QResizeEvent* e) override;
    void changeEvent(QEvent* event) override;

  private slots:
    void on_send();
    void on_attach_file();
    void on_new_session();
    void on_session_selected(int row);
    void on_delete_session();
    void on_rename_session();
    void on_stream_chunk(const QString& chunk, bool done);
    void on_streaming_done(ai_chat::LlmResponse response);
    void on_provider_changed();
    void on_search_changed(const QString& text);
    void on_typing_indicator_tick();
    void on_toggle_sidebar();

  private:
    // ── Sidebar ──────────────────────────────────────────────────────────
    QWidget* sidebar_ = nullptr;
    QLineEdit* search_edit_ = nullptr;
    QListWidget* session_list_ = nullptr;
    QPushButton* new_btn_ = nullptr;
    QPushButton* delete_btn_ = nullptr;
    QPushButton* rename_btn_ = nullptr;
    QLabel* provider_lbl_ = nullptr;
    QLabel* model_lbl_ = nullptr;

    // ── Sidebar collapse state ───────────────────────────────────────────
    QPushButton* sidebar_toggle_btn_ = nullptr;
    QPropertyAnimation* sidebar_anim_ = nullptr;
    bool sidebar_collapsed_ = false;
    static constexpr int kSidebarExpandedWidth = 280;
    void apply_sidebar_collapsed(bool collapsed, bool animate);

    // ── Chat header ──────────────────────────────────────────────────────
    QWidget* chat_widget_ = nullptr;
    QLabel* hdr_status_dot_ = nullptr;
    QLabel* hdr_status_lbl_ = nullptr;
    QLabel* hdr_session_lbl_ = nullptr;
    QLabel* hdr_model_lbl_ = nullptr;
    QLabel* hdr_tokens_lbl_ = nullptr;

    // ── Chat area ────────────────────────────────────────────────────────
    QScrollArea* scroll_area_ = nullptr;
    QWidget* messages_container_ = nullptr;
    QVBoxLayout* messages_layout_ = nullptr;
    QWidget* welcome_panel_ = nullptr;
    QPlainTextEdit* input_box_ = nullptr;
    QPushButton* send_btn_ = nullptr;
    QPushButton* attach_btn_ = nullptr;
    QLabel* attach_badge_ = nullptr; // shows attached file name
    QString attached_file_path_;

    // ── Typing indicator ─────────────────────────────────────────────────
    QWidget* typing_indicator_ = nullptr;
    QLabel* typing_dots_lbl_ = nullptr;
    QTimer* typing_timer_ = nullptr;
    int typing_step_ = 0;

    // ── State ────────────────────────────────────────────────────────────
    QString active_session_id_;
    // Snapshot of request‑time context – used by the async response handler
    QString pending_req_session_;
    QString pending_req_provider_;
    QString pending_req_model_;
    QString active_session_title_;
    mutable QMutex history_mutex_;
    std::vector<ai_chat::ConversationMessage> history_;
    bool streaming_ = false;
    bool scroll_pending_ = false;
    QPointer<QLabel> streaming_bubble_;
    int total_tokens_ = 0;
    int total_messages_ = 0;

    // ── Per-stream "Thinking" (chain-of-thought) section ─────────────────────
    // Reasoning models stream their thoughts on a separate channel (see
    // think_stream_prefix()). We collect them into a collapsible card inserted
    // ABOVE the answer bubble so the answer stays clean. Reset between messages.
    QPointer<QWidget> thinking_card_;
    QPointer<QPushButton> thinking_header_;
    QPointer<QLabel> thinking_body_;
    QString thinking_text_;

    // ── Build ────────────────────────────────────────────────────────────
    void build_ui();
    void retranslateUi();
    void build_sidebar();
    void build_chat_area();
    QWidget* build_header_bar();
    QWidget* build_welcome();
    QWidget* build_input_area();
    QWidget* build_typing_indicator();
    void refresh_theme();

    // ── Data ─────────────────────────────────────────────────────────────
    void load_sessions();
    void load_messages(const QString& session_id);
    void create_new_session();
    void add_message_bubble(const QString& role, const QString& content, const QString& timestamp = {});
    QLabel* add_streaming_bubble();
    // Collapsible "Thinking" card for the in-flight assistant message.
    void append_thinking_chunk(const QString& text);
    void create_thinking_card();
    void finalize_thinking_card();
    void reset_thinking_state();
    void clear_messages();
    void scroll_to_bottom();
    void set_input_enabled(bool enabled);
    void update_stats();
    void show_welcome(bool show);
    void show_typing(bool show);

    // EventBus subscriptions — registered in showEvent, released in hideEvent.
    // MCP set_active_llm publishes llm.provider_changed when the LLM (or
    // Finagent) switches the active provider. We force-reload LlmService so
    // the next message uses the new provider; LlmService::config_changed
    // signal then triggers on_provider_changed for header refresh.
    QList<EventBus::HandlerId> mcp_event_subs_;
    void subscribe_mcp_events();
    void unsubscribe_mcp_events();

    // Phase 7 linking. SymbolGroup::None when unlinked.
    fincept::SymbolGroup link_group_ = fincept::SymbolGroup::None;
    // Last symbol received from the linked group. Saved as the screen's
    // "current_symbol" so the link badge reflects the most recent context.
    // Used to prefix the next user-sent message with "[Context: <SYMBOL>]"
    // so the LLM has the security in scope without the user having to type
    // it. Consumed (one-shot) on send; the linked symbol persists so the
    // badge keeps showing until the group changes.
    fincept::SymbolRef linked_symbol_;
};

} // namespace fincept::screens
