//
// Created by arjun-flowylabs on 1/10/2026.
//

#include "MainWindow.h"
#include "dialogs/authdialog.h"
#include "authmanager.h"
#include "dialogs/createstreamdialog.h"
#include "dialogs/memberpickerdialog.h"
#include "widgets/networkdetailwidget.h"
#include "networkmanager.h"
#include "dialogs/settingsdialog.h"
#include "dialogs/textinputdialog.h"
#include <QApplication>
#include <QJsonDocument>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QLabel>
#include <QListView>
#include <QListWidget>
#include <QMenu>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QJsonObject>
#include <QPushButton>
#include <QSplitter>
#include <QStatusBar>
#include <QToolButton>
#include <QTreeView>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "media/mediahandler.h"
#include "dialogs/mediapreviewdialog.h"
#include "mediaparticlegenerator.h"
#include "widgets/textparticlewidget.h"
#include "widgets/mediaparticlewidget.h"
#include <QStackedWidget>
#include <QUrl>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), m_trayIcon(nullptr), m_networkDetailWidget(nullptr),
      m_authManager(new AuthManager(this)), m_authDialog(nullptr), m_settingsDialog(nullptr),
      m_textInputDialog(nullptr), m_createStreamDialog(nullptr),
      m_store(nullptr), m_networkStreamModel(nullptr), m_particleListModel(nullptr),
      m_selectedParticleRow(-1), m_isDragging(false), m_media{new MediaHandler{this}},
      m_spaceHeld(false)
{
  m_authDialog = new AuthDialog(this);
  m_textInputDialog = new TextInputDialog(this);
  connect(m_textInputDialog, &TextInputDialog::textSubmitted, this, &MainWindow::onTextMessageSubmitted);

  buildUi();

  m_topBar->setCursor(Qt::OpenHandCursor);

  // Enable frameless window for edge-to-edge experience
  setWindowFlags(Qt::FramelessWindowHint | Qt::Window);
  setAttribute(Qt::WA_TranslucentBackground, false);

  // Style for grey status bar text
  QString statusBarLabelStyle = "QLabel { color: #808080; }";
  QString pingLabelStyle = "QLabel { color: #00AA00; }"; // Green for ping

  m_currentPathLabel = new QLabel(this);
  m_currentPathLabel->setMargin(5);
  m_currentPathLabel->setStyleSheet(statusBarLabelStyle);
  QFont font = QFont();
  font.setStyle(QFont::StyleItalic);
  m_currentPathLabel->setFont(font);
  m_statusBar->addWidget(m_currentPathLabel);

  // Add spacer to push right-aligned items to the right
  m_statusBar->addWidget(new QLabel(""), 1);

  // Ping indicator (green text)
  m_pingLabel = new QLabel(this);
  m_pingLabel->setMargin(5);
  m_pingLabel->setMinimumWidth(100);
  m_pingLabel->setAlignment(Qt::AlignCenter);
  m_pingLabel->setStyleSheet(pingLabelStyle);
  m_statusBar->addPermanentWidget(m_pingLabel);

  // Position indicator (vim-style)
  m_positionLabel = new QLabel(this);
  m_positionLabel->setMargin(5);
  m_positionLabel->setMinimumWidth(50);
  m_positionLabel->setAlignment(Qt::AlignCenter);
  m_positionLabel->setStyleSheet(statusBarLabelStyle);
  m_statusBar->addPermanentWidget(m_positionLabel);

  // Storage indicator
  m_storageLabel = new QLabel(this);
  m_storageLabel->setMargin(5);
  m_storageLabel->setMinimumWidth(60);
  m_storageLabel->setAlignment(Qt::AlignCenter);
  m_storageLabel->setStyleSheet(statusBarLabelStyle);
  m_statusBar->addPermanentWidget(m_storageLabel);

  // Setup ping timer for periodic server connectivity check
  m_pingTimer = new QTimer(this);
  connect(m_pingTimer, &QTimer::timeout, this, []() {
    NetworkManager::instance().ping();
  });
  connect(&NetworkManager::instance(), &NetworkManager::pingResult, this, [this](int ms) {
    m_pingLabel->setText("connected " + QString::number(ms) + "ms");
    m_pingLabel->setStyleSheet("QLabel { color: #00AA00; }");
  });
  connect(&NetworkManager::instance(), &NetworkManager::pingFailed, this, [this]() {
    m_pingLabel->setText("disconnected");
    m_pingLabel->setStyleSheet("QLabel { color: #AA0000; }");
  });
  m_pingTimer->start(10000);
  NetworkManager::instance().ping();

  m_splitter->setStretchFactor(0, 1);
  m_splitter->setStretchFactor(1, 4);
  m_splitter->setStretchFactor(2, 1);

  setupModels();

  m_authDialog->setModal(true);

  connect(m_authManager, &AuthManager::codeSentToEmail, m_authDialog, &AuthDialog::onCodeSentToEmail);
  connect(m_authManager, &AuthManager::errorOccurred, m_authDialog, &AuthDialog::showError);
  connect(m_authManager, &AuthManager::signedIn, m_authDialog, &AuthDialog::hide);
  connect(m_authDialog, &AuthDialog::codeRequested, m_authManager, &AuthManager::requestSignInCode);
  connect(m_authDialog, &AuthDialog::signInRequested, m_authManager, &AuthManager::signIn);
  connect(m_authManager, &AuthManager::signedIn, m_authDialog, &AuthDialog::reset);
  connect(m_authManager, &AuthManager::signedOut, m_authDialog, &AuthDialog::reset);
  connect(m_authManager, &AuthManager::signedOut, m_authDialog, &AuthDialog::show);
  connect(m_authManager, &AuthManager::signedIn, this, &MainWindow::onSignedIn);
  connect(m_store, &Store::startupDataLoaded, m_treeView, &QTreeView::expandAll);
  connect(m_store, &Store::particleUpdated, this, &MainWindow::onParticleUpdated);

  // DocumentSend toolbar button opens text input dialog
  connect(m_sendTextButton, &QToolButton::clicked, this, &MainWindow::showTextInputDialog);

  // Explicit connects for buttons (no auto-connect without .ui)
  connect(m_settingsButton, &QToolButton::clicked, this, &MainWindow::on_settingsButton_clicked);
  connect(m_exitButton, &QToolButton::clicked, this, &MainWindow::on_exitButton_clicked);

  // "New stream" button
  m_createStreamDialog = new CreateStreamDialog(this);
  connect(m_newStreamButton, &QPushButton::clicked, this, &MainWindow::onNewStreamClicked);
  connect(m_createStreamDialog, &CreateStreamDialog::streamRequested, this, &MainWindow::onCreateStreamRequested);

  // "Add members" toolbar button (ListAdd icon in right sidebar)
  connect(m_addMembersButton, &QToolButton::clicked, this, &MainWindow::onAddMembersClicked);

  m_authManager->tryRestoreSession();

  connect(m_media, &MediaHandler::errorOccurred, this, [this](const QString &message) {
    m_statusBar->showMessage(message);
  });

  m_mediaPreviewDialog = new MediaPreviewDialog(this);
  m_mediaParticleGenerator = new MediaParticleGenerator(m_store, this);

  connect(m_media, &MediaHandler::recordingComplete, this,
    [this](const QUrl &url, qint64 durationMs, const QString &mimeType) {
      m_media->stop();
      m_recordedFileUrl = url;
      m_recordedDurationMs = durationMs;
      m_recordedMimeType = mimeType;
      m_mediaPreviewDialog->showPreview(url);
  });

  connect(m_mediaPreviewDialog, &MediaPreviewDialog::spaceReleased, this, [this]() {
    m_spaceHeld = false;
    m_media->recordStop();
  });

  connect(m_mediaPreviewDialog, &QDialog::accepted, this, [this]() {
    m_mediaPreviewDialog->reset();
    if (m_selectedStreamId.isEmpty() || m_selectedNetworkId.isEmpty()) return;
    m_mediaParticleGenerator->generate(
        m_recordedFileUrl, m_recordedMimeType,
        m_selectedNetworkId, m_recordedDurationMs, m_selectedStreamId);
  });

  connect(m_mediaPreviewDialog, &QDialog::rejected, this, [this]() {
    m_mediaPreviewDialog->reset();
  });

  connect(m_mediaParticleGenerator, &MediaParticleGenerator::errorOccurred, this,
    [this](const QString &msg) { m_statusBar->showMessage(msg); });

  setupTrayIcon();
}

void MainWindow::buildUi()
{
  resize(650, 500);
  setWindowTitle("Flowy.llink");

  auto *centralWidget = new QWidget(this);
  setCentralWidget(centralWidget);
  auto *mainLayout = new QVBoxLayout(centralWidget);
  mainLayout->setContentsMargins(0, 0, 0, 0);

  m_splitter = new QSplitter(Qt::Horizontal);
  mainLayout->addWidget(m_splitter);

  // ── Left sidebar ──
  m_leftSidebar = new QWidget();
  m_leftSidebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  auto *leftLayout = new QVBoxLayout(m_leftSidebar);
  leftLayout->setSpacing(5);
  leftLayout->setContentsMargins(2, 2, 2, 2);

  // Top bar (drag area)
  m_topBar = new QWidget();
  m_topBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
  m_topBar->setMinimumHeight(20);
  auto *topBarLayout = new QHBoxLayout(m_topBar);
  topBarLayout->setSpacing(0);
  topBarLayout->setContentsMargins(0, 0, 0, 0);

  m_settingsButton = new QToolButton();
  m_settingsButton->setText("...");
  m_settingsButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::HelpAbout));
  topBarLayout->addWidget(m_settingsButton);

  topBarLayout->addStretch();

  m_exitButton = new QToolButton();
  m_exitButton->setText("...");
  m_exitButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit));
  topBarLayout->addWidget(m_exitButton);

  leftLayout->addWidget(m_topBar);

  // Tree view
  m_treeView = new QTreeView();
  m_treeView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  leftLayout->addWidget(m_treeView);

  // New stream button
  m_newStreamButton = new QPushButton("New stream");
  m_newStreamButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ListAdd));
  leftLayout->addWidget(m_newStreamButton);

  m_splitter->addWidget(m_leftSidebar);

  // ── Content view ──
  m_contentView = new QWidget();
  m_contentView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  m_contentView->setMinimumWidth(350);
  auto *contentLayout = new QVBoxLayout(m_contentView);
  contentLayout->setSpacing(2);
  contentLayout->setContentsMargins(0, 0, 0, 2);

  // Stacked widget for particle type-specific content
  m_contentStack = new QStackedWidget();
  m_contentStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  m_textParticleWidget = new TextParticleWidget();
  m_mediaParticleWidget = new MediaParticleWidget();

  m_contentStack->addWidget(m_textParticleWidget);
  m_contentStack->addWidget(m_mediaParticleWidget);

  contentLayout->addWidget(m_contentStack);

  m_creatorLabel = new QLabel();
  QFont creatorFont;
  creatorFont.setPointSize(15);
  m_creatorLabel->setFont(creatorFont);
  m_creatorLabel->setAlignment(Qt::AlignCenter);
  contentLayout->addWidget(m_creatorLabel);

  m_ackLabel = new QLabel();
  m_ackLabel->setAlignment(Qt::AlignCenter);
  contentLayout->addWidget(m_ackLabel);

  // Content toolbar (empty, matches widget_4 from .ui)
  auto *contentToolbar = new QWidget();
  auto *contentToolbarLayout = new QHBoxLayout(contentToolbar);
  contentToolbarLayout->setSpacing(2);
  contentToolbarLayout->setContentsMargins(8, 0, 0, 0);
  contentLayout->addWidget(contentToolbar);

  m_splitter->addWidget(m_contentView);

  // ── Right sidebar ──
  m_rightSidebar = new QWidget();
  m_rightSidebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  auto *rightLayout = new QVBoxLayout(m_rightSidebar);
  rightLayout->setSpacing(2);
  rightLayout->setContentsMargins(2, 2, 2, 2);

  // Particle list view
  m_particlesView = new QListView();
  m_particlesView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  auto sp1 = m_particlesView->sizePolicy();
  sp1.setVerticalStretch(2);
  m_particlesView->setSizePolicy(sp1);
  rightLayout->addWidget(m_particlesView);

  // Members list
  m_membersList = new QListWidget();
  m_membersList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  auto sp2 = m_membersList->sizePolicy();
  sp2.setVerticalStretch(1);
  m_membersList->setSizePolicy(sp2);
  rightLayout->addWidget(m_membersList);

  // "Hold space to speak" label
  auto *holdSpaceLabel = new QLabel("Hold space to speak");
  holdSpaceLabel->setAlignment(Qt::AlignCenter);
  QPalette holdPalette = holdSpaceLabel->palette();
  QColor holdColor(153, 156, 145, 217);
  holdPalette.setColor(QPalette::WindowText, holdColor);
  holdSpaceLabel->setPalette(holdPalette);
  rightLayout->addWidget(holdSpaceLabel);

  // Empty toolbar row (widget_5)
  auto *emptyToolbar = new QWidget();
  auto *emptyToolbarLayout = new QHBoxLayout(emptyToolbar);
  emptyToolbarLayout->setSpacing(2);
  emptyToolbarLayout->setContentsMargins(0, 0, 0, 0);
  rightLayout->addWidget(emptyToolbar);

  // RTL toolbar row (widget_3)
  auto *rtlToolbar = new QWidget();
  rtlToolbar->setLayoutDirection(Qt::RightToLeft);
  auto *rtlToolbarLayout = new QHBoxLayout(rtlToolbar);
  rtlToolbarLayout->setSpacing(2);
  rtlToolbarLayout->setContentsMargins(0, 0, 0, 0);

  auto *editClearButton = new QToolButton();
  editClearButton->setText("...");
  editClearButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditClear));
  editClearButton->setToolTip(QStringLiteral("Close stream"));
  rtlToolbarLayout->addWidget(editClearButton);

  m_addMembersButton = new QToolButton();
  m_addMembersButton->setText("...");
  m_addMembersButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ListAdd));
  m_addMembersButton->setToolTip(QStringLiteral("Add members to stream"));
  rtlToolbarLayout->addWidget(m_addMembersButton);

  auto *insertImageButton = new QToolButton();
  insertImageButton->setText("...");
  insertImageButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::InsertImage));
  insertImageButton->setToolTip(QStringLiteral("Attach files"));
  rtlToolbarLayout->addWidget(insertImageButton);

  m_sendTextButton = new QToolButton();
  m_sendTextButton->setText("...");
  m_sendTextButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSend));
  m_sendTextButton->setToolTip(QStringLiteral("Send text message"));
  rtlToolbarLayout->addWidget(m_sendTextButton);

  auto *cameraVideoButton = new QToolButton();
  cameraVideoButton->setText("...");
  cameraVideoButton->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::CameraVideo));
  cameraVideoButton->setToolTip(QStringLiteral("Toggle camera mode"));
  rtlToolbarLayout->addWidget(cameraVideoButton);

  rightLayout->addWidget(rtlToolbar);

  m_splitter->addWidget(m_rightSidebar);

  QFrame* hSeparator = new QFrame();
  hSeparator->setFrameShape(QFrame::HLine);
  hSeparator->setFrameShadow(QFrame::Plain);
  hSeparator->setStyleSheet("color: rgba(128, 128, 128, 0.3);");
  hSeparator->setFixedHeight(1);
  mainLayout->addWidget(hSeparator);

  // ── Network detail widget (hidden by default) ──

  m_statusBar = new QStatusBar();
  setStatusBar(m_statusBar);
}

void MainWindow::setupTrayIcon()
{
  m_trayIcon = new QSystemTrayIcon(this);
  m_trayIcon->setIcon(QIcon(":/assets/logo.png"));
  m_trayIcon->setToolTip("llink");

  QMenu *trayMenu = new QMenu(this);
  trayMenu->addAction("Show", this, &MainWindow::show);
  trayMenu->addAction("Quit", qApp, &QApplication::quit);
  m_trayIcon->setContextMenu(trayMenu);

  connect(m_trayIcon, &QSystemTrayIcon::activated, this, [this](QSystemTrayIcon::ActivationReason reason) {
    if (reason == QSystemTrayIcon::Trigger)
    {
      isVisible() ? hide() : show();
    }
  });

  m_trayIcon->show();
}

MainWindow::~MainWindow()
{
  if (m_spaceHeld)
  {
    m_media->stop();
  }
}

void MainWindow::on_exitButton_clicked()
{
  qApp->exit(0);
}

void MainWindow::on_settingsButton_clicked()
{
  if (!m_settingsDialog)
  {
    m_settingsDialog = new SettingsDialog(this);
    connect(m_settingsDialog, &SettingsDialog::signOutRequested, m_authManager, &AuthManager::signOut);
    connect(m_settingsDialog, &SettingsDialog::createNetworkRequested, this, [this](const QString &name) {
      m_store->createNetwork(name);
    });
  }
  if (m_authManager->sessionData())
  {
    m_settingsDialog->setAuthLabel("Hello, " + m_authManager->sessionData()->emailPrefix);
  }
  m_settingsDialog->show();
}

void MainWindow::setupModels()
{
  // Create store (data loaded after sign-in via loadStartupData)
  m_store = new Store(this);

  m_networkDetailWidget = new NetworkDetailWidget(this);
  m_splitter->addWidget(m_networkDetailWidget);
  m_splitter->setStretchFactor(3, 4);
  m_networkDetailWidget->hide();

  connect(m_store, &Store::networksChanged, this, &MainWindow::onNetworksChanged);
  connect(m_networkDetailWidget, &NetworkDetailWidget::addMemberRequested, this, &MainWindow::onAddNetworkMemberRequested);

  // Create and set tree model
  m_networkStreamModel = new NetworkStreamModel(m_store, this);
  m_treeView->setModel(m_networkStreamModel);
  m_treeView->setIndentation(5);
  m_treeView->setHeaderHidden(true);
  m_treeView->expandAll();

  // Configure column behavior: name stretches, unseen count is fixed width
  m_treeView->header()->setStretchLastSection(false);
  m_treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
  m_treeView->header()->setSectionResizeMode(1, QHeaderView::Fixed);
  m_treeView->setColumnWidth(1, 40);

  // Create and set list model
  m_particleListModel = new ParticleListModel(m_store, this);
  m_particlesView->setModel(m_particleListModel);

  // Configure particle list view to use ellipses for long text
  m_particlesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  m_particlesView->setTextElideMode(Qt::ElideRight);

  // Connect selection changes
  connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
          &MainWindow::onTreeSelectionChanged);

  // Connect particle selection changes
  connect(m_particlesView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
          &MainWindow::onParticleSelectionChanged);

  // Install event filter to capture key presses from child views
  m_treeView->installEventFilter(this);
  m_particlesView->installEventFilter(this);
}

void MainWindow::onSignedIn()
{
  m_store->setCurrentUserEmail(m_authManager->sessionData()->email);
  m_store->loadStartupData();
}

void MainWindow::onParticleUpdated(const QString &streamId, const QString &particleId)
{
  Q_UNUSED(streamId);

  if (particleId != m_selectedParticleId)
    return;

  const Particle *particle = m_store->particleById(particleId);
  if (particle && !particle->ackedByEmails.empty())
  {
    QStringList acked;
    for (const auto &email : particle->ackedByEmails)
      acked.append(email);
    m_ackLabel->setText("Acked by: " + acked.join(", "));
  }
  else
  {
    m_ackLabel->setText("");
  }
}

void MainWindow::onNewStreamClicked()
{
  if (m_selectedNetworkId.isEmpty())
  {
    return;
  }
  const Network *network = m_store->networkById(m_selectedNetworkId);
  if (network)
  {
    m_createStreamDialog->setNetworkMembers(network->members);
  }
  m_createStreamDialog->show();
  m_createStreamDialog->raise();
  m_createStreamDialog->activateWindow();
}

void MainWindow::onCreateStreamRequested(const QString &name, const QString &visibility, const QStringList &members)
{
  m_store->createStream(m_selectedNetworkId, name, "", visibility, members);
}

void MainWindow::onAddMembersClicked()
{
  if (m_selectedStreamId.isEmpty() || m_selectedNetworkId.isEmpty())
  {
    return;
  }
  const Network *network = m_store->networkById(m_selectedNetworkId);
  const Stream *stream = m_store->streamById(m_selectedStreamId);
  if (!network || !stream)
  {
    return;
  }

  MemberPickerDialog picker("Add Members", this);
  picker.setMembers(network->members, stream->memberEmails);

  if (picker.exec() == QDialog::Accepted)
  {
    QStringList emails = picker.selectedEmails();
    if (!emails.isEmpty())
    {
      auto *op = m_store->addStreamMembers(m_selectedStreamId, emails);
      connect(op, &Operation::success, this, [this](const QJsonDocument &) {
        auto *fetchOp = m_store->fetchStream(m_selectedStreamId);
        connect(fetchOp, &Operation::success, this, [this](const QJsonDocument &) {
          m_membersList->clear();
          const Stream *s = m_store->streamById(m_selectedStreamId);
          if (s)
          {
            for (const QString &email : s->memberEmails)
            {
              m_membersList->addItem(email.split("@")[0]);
            }
          }
        });
      });
    }
  }
}

void MainWindow::onNetworksChanged()
{
  if (!m_selectedNetworkId.isEmpty() && m_networkDetailWidget->isVisible())
  {
    const Network *network = m_store->networkById(m_selectedNetworkId);
    if (network)
    {
      m_networkDetailWidget->setNetwork(*network, m_authManager->sessionData() ? m_authManager->sessionData()->email : QString());
    }
    else
    {
      m_networkDetailWidget->clear();
    }
  }
}

void MainWindow::onAddNetworkMemberRequested(const QString &networkId, const QString &email)
{
  auto *op = m_store->addNetworkMembers(networkId, {email});
  connect(op, &Operation::success, this, [this, networkId](const QJsonDocument &) {
    m_store->fetchNetwork(networkId);
  });
}

void MainWindow::onTreeSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
  Q_UNUSED(deselected);

  if (selected.indexes().isEmpty())
  {
    m_particleListModel->setStreamId(QString());
    m_membersList->clear();
    m_networkDetailWidget->hide();
    m_contentView->show();
    m_rightSidebar->show();
    return;
  }

  QModelIndex index = selected.indexes().first();

  if (m_networkStreamModel->isStreamItem(index))
  {
    // Show normal 3-pane view
    m_networkDetailWidget->hide();
    m_contentView->show();
    m_rightSidebar->show();

    QString streamId = m_networkStreamModel->streamIdFromIndex(index);
    m_particleListModel->setStreamId(streamId);
    m_selectedStreamId = streamId;

    // Also track the parent network
    QModelIndex parentIndex = m_networkStreamModel->parent(index);
    QString networkId = m_networkStreamModel->networkIdFromIndex(parentIndex);
    m_selectedNetworkId = networkId;

    // Show stream members
    m_membersList->clear();
    const Stream *stream = m_store->streamById(streamId);
    if (stream)
    {
      for (const QString &email : stream->memberEmails)
      {
        m_membersList->addItem(email.split("@")[0]);
      }
    }

    // Auto-select first unseen particle (or first particle if all seen)
    int unseenRow = m_particleListModel->firstUnseenRow();
    if (unseenRow >= 0)
    {
      m_particlesView->setCurrentIndex(m_particleListModel->index(unseenRow, 0));
      m_particlesView->setFocus();
    }
    else if (m_particleListModel->rowCount() > 0)
    {
      m_particlesView->setCurrentIndex(m_particleListModel->index(m_particleListModel->rowCount() - 1, 0));
      m_particlesView->setFocus();
    }
  }
  else // network selected
  {
    m_particleListModel->setStreamId(QString());
    m_selectedStreamId.clear();
    m_selectedParticleRow = -1;
    m_membersList->clear();

    QString networkId = m_networkStreamModel->networkIdFromIndex(index);
    m_selectedNetworkId = networkId;

    // Show network detail widget
    const Network *network = m_store->networkById(networkId);
    if (network)
    {
      m_networkDetailWidget->setNetwork(*network, m_authManager->sessionData() ? m_authManager->sessionData()->email : QString());
    }
    else
    {
      m_networkDetailWidget->clear();
    }
    m_contentView->hide();
    m_rightSidebar->hide();
    m_networkDetailWidget->show();
  }

  updateStatusBar();
}

void MainWindow::onParticleSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
  Q_UNUSED(deselected);

  if (selected.indexes().isEmpty())
  {
    m_textParticleWidget->clear();
    m_mediaParticleWidget->clear();
    m_creatorLabel->setText("");
    m_ackLabel->setText("");
    m_selectedParticleId.clear();
    m_selectedParticleRow = -1;
    updateStatusBar();
    return;
  }

  QModelIndex index = selected.indexes().first();
  m_selectedParticleRow = index.row();
  const Particle *particle = m_particleListModel->particleAtRow(index.row());
  if (particle)
  {
    m_creatorLabel->setText(particle->createdByEmail);
    m_selectedParticleId = particle->id;

    if (particle->type == "text")
    {
      m_mediaParticleWidget->clear();
      m_textParticleWidget->setParticle(particle);
      m_contentStack->setCurrentWidget(m_textParticleWidget);
    }
    else if (particle->type == "media")
    {
      m_textParticleWidget->clear();
      m_mediaParticleWidget->setParticle(particle);
      m_contentStack->setCurrentWidget(m_mediaParticleWidget);
    }

    // Show ack info
    if (!particle->ackedByEmails.empty())
    {
      QStringList acked;
      for (const auto &email : particle->ackedByEmails)
      {
        acked.append(email);
      }
      m_ackLabel->setText("Acked by: " + acked.join(", "));
    }
    else
    {
      m_ackLabel->setText("");
    }

    // Mark seen on selection
    if (!particle->seen)
    {
      m_store->markParticleSeen(particle->id);
    }
  }

  updateStatusBar();
}

void MainWindow::updateStatusBar()
{
  QStringList pathComponents;

  // Add network if selected
  if (!m_selectedNetworkId.isEmpty())
  {
    const Network *network = m_store->networkById(m_selectedNetworkId);
    if (network)
    {
      pathComponents << network->name;
    }
  }

  // Add stream if selected
  if (!m_selectedStreamId.isEmpty())
  {
    const Stream *stream = m_store->streamById(m_selectedStreamId);
    if (stream)
    {
      pathComponents << stream->name;
    }
  }

  // Add particle if selected
  if (!m_selectedParticleId.isEmpty())
  {
    const Particle *particle = m_store->particleById(m_selectedParticleId);
    if (particle)
    {
      pathComponents << "p_" + particle->id.right(5);
    }
  }

  m_currentPathLabel->setText(pathComponents.join(" > "));

  // Update position indicator (vim-style)
  if (!m_selectedStreamId.isEmpty())
  {
    int totalCount = m_particleListModel->rowCount();
    if (totalCount == 0)
    {
      m_positionLabel->setText("");
    }
    else if (totalCount == 1)
    {
      m_positionLabel->setText("All");
    }
    else if (m_selectedParticleRow == 0)
    {
      m_positionLabel->setText("Top");
    }
    else if (m_selectedParticleRow == totalCount - 1)
    {
      m_positionLabel->setText("Bot");
    }
    else if (m_selectedParticleRow >= 0)
    {
      int percent = (m_selectedParticleRow * 100) / (totalCount - 1);
      m_positionLabel->setText(QString::number(percent) + "%");
    }
    else
    {
      m_positionLabel->setText("");
    }

    // Update data size indicator for selected particle
    if (!m_selectedParticleId.isEmpty())
    {
      const Particle *particle = m_store->particleById(m_selectedParticleId);
      if (particle)
      {
        QJsonObject dataObj;
        for (auto it = particle->data.constBegin(); it != particle->data.constEnd(); ++it)
        {
          dataObj.insert(it.key(), QJsonValue::fromVariant(it.value()));
        }
        int bytes = QJsonDocument(dataObj).toJson(QJsonDocument::Compact).size();
        if (bytes < 1024)
          m_storageLabel->setText(QString::number(bytes) + " B");
        else
          m_storageLabel->setText(QString::number(bytes / 1024) + " kB");
      }
      else
      {
        m_storageLabel->setText("");
      }
    }
    else
    {
      m_storageLabel->setText("");
    }
  }
  else
  {
    m_positionLabel->setText("");
    m_storageLabel->setText("");
  }
}


void MainWindow::showTextInputDialog()
{
  if (m_selectedStreamId.isEmpty())
  {
    return;
  }

  m_textInputDialog->show();
  m_textInputDialog->raise();
  m_textInputDialog->activateWindow();
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
  if (event->type() == QEvent::KeyPress)
  {
    auto *keyEvent = static_cast<QKeyEvent *>(event);
    if (keyEvent->key() == Qt::Key_Space && !keyEvent->isAutoRepeat() && !m_spaceHeld)
    {
      if (!m_selectedNetworkId.isEmpty() && !m_selectedStreamId.isEmpty())
      {
        m_spaceHeld = true;
        m_mediaPreviewDialog->showRecording();
        m_media->startRecording(m_mediaPreviewDialog->videoSink());
        return true;
      }
    }
    if (keyEvent->key() == Qt::Key_T && keyEvent->modifiers() == Qt::NoModifier && !m_selectedStreamId.isEmpty())
    {
      showTextInputDialog();
      return true;
    }
    if (keyEvent->key() == Qt::Key_A && keyEvent->modifiers() == Qt::NoModifier && !m_selectedParticleId.isEmpty())
    {
      m_store->ackParticle(m_selectedParticleId);
      return true;
    }
  }
  if (event->type() == QEvent::KeyRelease)
  {
    auto *keyEvent = static_cast<QKeyEvent *>(event);
    if (keyEvent->key() == Qt::Key_Space && !keyEvent->isAutoRepeat() && m_spaceHeld)
    {
      m_spaceHeld = false;
      m_media->recordStop();
      return true;
    }
  }
  return QMainWindow::eventFilter(obj, event);
}

void MainWindow::onTextMessageSubmitted(const QString &text)
{
  if (m_selectedStreamId.isEmpty())
  {
    return;
  }

  auto *op = m_store->createParticle(m_selectedStreamId, "text", {{"content", text}});
  connect(op, &Operation::success, this, [this](const QJsonDocument &) {
    int lastRow = m_particleListModel->rowCount() - 1;
    if (lastRow >= 0)
    {
      m_particlesView->setCurrentIndex(m_particleListModel->index(lastRow, 0));
      m_particlesView->setFocus();
    }
  });
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
  QMainWindow::keyPressEvent(event);
}

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
  QMainWindow::keyReleaseEvent(event);
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
  if (event->button() == Qt::LeftButton)
  {
    // Check if the click is within the top bar widget area
    if (m_topBar && m_topBar->geometry().contains(event->pos()))
    {
      m_isDragging = true;
      setCursor(Qt::ClosedHandCursor);
      m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
      event->accept();
      return;
    }
  }
  QMainWindow::mousePressEvent(event);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
  if (m_isDragging && (event->buttons() & Qt::LeftButton))
  {
    move(event->globalPosition().toPoint() - m_dragPosition);
    event->accept();
    return;
  }
  QMainWindow::mouseMoveEvent(event);
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
  if (event->button() == Qt::LeftButton)
  {
    m_isDragging = false;
    unsetCursor();
  }
  QMainWindow::mouseReleaseEvent(event);
}
