#include "mainwindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QSettings>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QWebEngineProfile>
#include <QWebEnginePage>
#include <QWebEngineSettings>
#include <QLabel>
#include <QTimer>
#include <QCheckBox>
#include <QApplication>
#include <QStyle>

ThumbnailWidget::ThumbnailWidget(const QString& ip, QWidget* parent) : QWidget(parent), ipAddress(ip), isConnected(false) {
    QVBoxLayout* layout = new QVBoxLayout(this);
    
    QHBoxLayout* headerLayout = new QHBoxLayout();
    QLabel* label = new QLabel(ip);
    
    rearCamCb = new QCheckBox("Rear Cam");
    micCb = new QCheckBox("Mic");
    flashCb = new QCheckBox("Flash");
    buzzerCb = new QCheckBox("Buzzer");
    softResetBtn = new QPushButton("Soft Reset");
    softResetBtn->setStyleSheet("background-color: #e64553; color: white; font-weight: bold; padding: 3px 8px; border: 1px solid #d20f39; border-radius: 4px;");
    
    QPushButton* deleteBtn = new QPushButton("X");
    deleteBtn->setFixedSize(20, 20);
    deleteBtn->setStyleSheet("color: red; font-weight: bold;");
    
    headerLayout->addWidget(label);
    headerLayout->addWidget(rearCamCb);
    headerLayout->addWidget(micCb);
    headerLayout->addWidget(flashCb);
    headerLayout->addWidget(buzzerCb);
    headerLayout->addWidget(softResetBtn);
    headerLayout->addStretch();
    headerLayout->addWidget(deleteBtn);
    
    connect(flashCb, &QCheckBox::toggled, [this, ip](bool checked) {
        emit flashToggled(ip, checked);
    });
    connect(buzzerCb, &QCheckBox::toggled, [this, ip](bool checked) {
        emit buzzerToggled(ip, checked);
    });
    connect(softResetBtn, &QPushButton::clicked, [this, ip]() {
        emit softResetRequested(ip);
    });
    
    webView = new QWebEngineView(this);
    webView->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
    webView->setMinimumSize(320, 240);
    
    layout->addLayout(headerLayout);
    layout->addWidget(webView, 1);
    this->setMinimumSize(340, 280);
    
    connect(deleteBtn, &QPushButton::clicked, [this, ip]() {
        emit deleteRequested(ip);
    });
}

void ThumbnailWidget::setAudioVolume(int volume) {
    if (webView && isConnected) {
        webView->page()->runJavaScript(QString("if (typeof setAudioVolume === 'function') setAudioVolume(%1);").arg(volume / 100.0));
    }
}

void ThumbnailWidget::setAudioMuted(bool muted) {
    if (webView && isConnected) {
        webView->page()->runJavaScript(QString("if (typeof setAudioMuted === 'function') setAudioMuted(%1);").arg(muted ? "true" : "false"));
    }
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), m_isPlaying(false)
{
    setupDarkStyle();
    setupUi();
    setupSignalingServer();
    loadIniFile();

    QString deviceName = QString("PC_Node_%1").arg(QDateTime::currentMSecsSinceEpoch() % 1000);
    m_discoveryService = new UdpDiscoveryService(deviceName, this);
    m_discoveryService->setWatcherMode(true);
    connect(m_discoveryService, &UdpDiscoveryService::nodesUpdated, this, &MainWindow::onNodesUpdated);
    connect(m_discoveryService, &UdpDiscoveryService::signalingMessageReceived, this, &MainWindow::onUdpSignalingMessageReceived);
    m_discoveryService->start();

    m_opcUaServer = new OpcUaServer(this);
    m_opcUaServer->start();
    
    // Periodically create thumbnails for new nodes
    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, [this]() {
        for (const QString& ip : m_knownIps) {
            if (!m_thumbnails.contains(ip)) {
                createThumbnail(ip);
            }
        }
    });
    timer->start(5000);
}

MainWindow::~MainWindow() {
    m_clients.clear();
}

void MainWindow::setupUi() {
    this->setWindowTitle("Pehredaar - Security Surveillance & VOX Audio");
    this->resize(1024, 768);

    QWidget* centralWidget = new QWidget(this);
    QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget);

    QHBoxLayout* topBar = new QHBoxLayout();
    
    QPushButton* resetBtn = new QPushButton("Reset Sockets");
    resetBtn->setStyleSheet("background-color: #e64553; color: white; font-weight: bold; padding: 5px 10px; border: 1px solid #d20f39; border-radius: 4px;");
    
    m_playBtn = new QPushButton("Play");
    m_playBtn->setStyleSheet("background-color: green; color: white; font-weight: bold; padding: 5px;");
    
    m_saveBtn = new QPushButton("Save Nodes to INI");
    m_saveBtn->setStyleSheet("font-weight: bold; padding: 5px;");
    
    m_loadBtn = new QPushButton("Load Nodes from INI");
    m_loadBtn->setStyleSheet("font-weight: bold; padding: 5px;");
    
    topBar->addWidget(new QLabel("Security Surveillance System"));
    topBar->addStretch();
    topBar->addWidget(resetBtn);
    topBar->addWidget(m_playBtn);
    topBar->addWidget(m_saveBtn);
    topBar->addWidget(m_loadBtn);
    mainLayout->addLayout(topBar);

    connect(resetBtn, &QPushButton::clicked, this, &MainWindow::onResetSocketsClicked);
    connect(m_playBtn, &QPushButton::clicked, this, &MainWindow::onPlayClicked);
    connect(m_saveBtn, &QPushButton::clicked, this, &MainWindow::onSaveClicked);
    connect(m_loadBtn, &QPushButton::clicked, this, &MainWindow::loadIniFile);

    m_splitter = new QSplitter(Qt::Vertical, this);

    m_topTabs = new QTabWidget(m_splitter);
    m_codeEditor = new CodeEditor(m_topTabs);
    m_console = new QConsole(m_topTabs);

    // Build VOX Audio Track Selector Panel
    m_voxPanel = new QWidget(m_topTabs);
    QVBoxLayout* voxLayout = new QVBoxLayout(m_voxPanel);
    
    QHBoxLayout* voxControlsLayout = new QHBoxLayout();
    m_activeTrackLabel = new QLabel("Active Audio Track: None Selected", m_voxPanel);
    m_activeTrackLabel->setStyleSheet("font-weight: bold; color: #007acc;");
    
    m_masterMuteCb = new QCheckBox("Mute All Audio Tracks", m_voxPanel);
    QLabel* volLabel = new QLabel("Master Volume:", m_voxPanel);
    m_masterVolumeSlider = new QSlider(Qt::Horizontal, m_voxPanel);
    m_masterVolumeSlider->setRange(0, 100);
    m_masterVolumeSlider->setValue(80);
    m_masterVolumeSlider->setFixedWidth(150);

    voxControlsLayout->addWidget(m_activeTrackLabel);
    voxControlsLayout->addStretch();
    voxControlsLayout->addWidget(m_masterMuteCb);
    voxControlsLayout->addWidget(volLabel);
    voxControlsLayout->addWidget(m_masterVolumeSlider);

    m_audioTrackListWidget = new QListWidget(m_voxPanel);
    m_audioTrackListWidget->setSelectionMode(QAbstractItemView::MultiSelection);
    
    voxLayout->addLayout(voxControlsLayout);
    voxLayout->addWidget(new QLabel("Select Audio Tracks to Monitor (Android Node Audio Streams):", m_voxPanel));
    voxLayout->addWidget(m_audioTrackListWidget);

    connect(m_audioTrackListWidget, &QListWidget::itemSelectionChanged, this, &MainWindow::onAudioTrackSelectionChanged);
    connect(m_masterVolumeSlider, &QSlider::valueChanged, this, &MainWindow::onMasterVolumeChanged);
    connect(m_masterMuteCb, &QCheckBox::toggled, this, &MainWindow::onMasterMuteToggled);

    m_topTabs->addTab(m_voxPanel, "Surveillance Vidio Audio Tracks");
    m_topTabs->addTab(m_codeEditor, "Code Editor");
    m_topTabs->addTab(m_console, "Console");

    // Build Discovered & Saved Nodes Manager Panel
    m_nodesPanel = new QWidget(m_topTabs);
    QVBoxLayout* nodesLayout = new QVBoxLayout(m_nodesPanel);

    QHBoxLayout* topNodesBar = new QHBoxLayout();
    m_watcherModeCb = new QCheckBox("Watcher Mode (Silent Receiver)", m_nodesPanel);
    m_watcherModeCb->setChecked(true); // Default to Watcher mode
    m_watcherModeCb->setStyleSheet("font-weight: bold; color: #89b4fa;");

    m_watcherStatusLabel = new QLabel("🛡 Mode: Watcher (Not Broadcasting IP)", m_nodesPanel);
    m_watcherStatusLabel->setStyleSheet("font-weight: bold; color: #a6e3a1; background: #181825; padding: 4px 8px; border-radius: 4px; border: 1px solid #313244;");

    topNodesBar->addWidget(m_watcherModeCb);
    topNodesBar->addWidget(m_watcherStatusLabel);
    topNodesBar->addStretch();

    connect(m_watcherModeCb, &QCheckBox::toggled, this, &MainWindow::onWatcherModeToggled);

    // Target Node Information Header Box
    QGroupBox *boxRemoteHeader = new QGroupBox("Target Node Information", m_nodesPanel);
    QHBoxLayout *headerLayout = new QHBoxLayout(boxRemoteHeader);

    m_nodeStatusLed = new QCLED(this);
    m_nodeStatusLed->wht();
    headerLayout->addWidget(m_nodeStatusLed);

    m_lblSelectedNodeName = new QLabel("No Node Selected", this);
    m_lblSelectedNodeName->setStyleSheet("font-size: 14px; font-weight: bold; color: #89b4fa;");
    headerLayout->addWidget(m_lblSelectedNodeName, 1);

    m_lblSelectedNodeIp = new QLabel("IP: --.--.--.--", this);
    m_lblSelectedNodeIp->setStyleSheet("font-size: 13px; font-weight: bold; color: #a6e3a1;");
    headerLayout->addWidget(m_lblSelectedNodeIp);

    // Split view inside Discovered Nodes panel: Node List & Nodes Table
    QSplitter* nodesSplitter = new QSplitter(Qt::Horizontal, m_nodesPanel);

    QGroupBox* boxNodeList = new QGroupBox("Discovered Nodes Summary", nodesSplitter);
    QVBoxLayout* listLayout = new QVBoxLayout(boxNodeList);
    m_nodeListWidget = new QListWidget(boxNodeList);
    connect(m_nodeListWidget, &QListWidget::itemSelectionChanged, this, &MainWindow::onNodeSelectionChanged);
    listLayout->addWidget(m_nodeListWidget);
    nodesSplitter->addWidget(boxNodeList);

    QWidget* rightTableWidget = new QWidget(nodesSplitter);
    QVBoxLayout* tableLayout = new QVBoxLayout(rightTableWidget);

    m_nodesTable = new QTableWidget(rightTableWidget);
    m_nodesTable->setColumnCount(5);
    m_nodesTable->setHorizontalHeaderLabels(QStringList() << "Device Name" << "IP Address" << "Capabilities" << "Status" << "Actions");
    m_nodesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    m_nodesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_nodesTable->setSelectionMode(QAbstractItemView::ExtendedSelection);

    QHBoxLayout* actionControlsLayout = new QHBoxLayout();
    m_connectSelectedBtn = new QPushButton("Connect Selected Node(s)");
    m_connectSelectedBtn->setStyleSheet("background-color: #89b4fa; color: #11111b; font-weight: bold; padding: 6px 12px; border-radius: 4px;");

    m_connectAllBtn = new QPushButton("Connect All Discovered Nodes");
    m_connectAllBtn->setStyleSheet("background-color: #a6e3a1; color: #11111b; font-weight: bold; padding: 6px 12px; border-radius: 4px;");

    m_disconnectSelectedBtn = new QPushButton("Disconnect Selected");
    m_disconnectSelectedBtn->setStyleSheet("background-color: #f38ba8; color: #11111b; font-weight: bold; padding: 6px 12px; border-radius: 4px;");

    actionControlsLayout->addWidget(m_connectSelectedBtn);
    actionControlsLayout->addWidget(m_connectAllBtn);
    actionControlsLayout->addWidget(m_disconnectSelectedBtn);
    actionControlsLayout->addStretch();

    QHBoxLayout* manualLayout = new QHBoxLayout();
    QLabel* manualLabel = new QLabel("Manual Target Node IP:");
    m_manualIpEdit = new QLineEdit();
    m_manualIpEdit->setPlaceholderText("e.g. 192.168.1.100");
    m_manualConnectBtn = new QPushButton("Add & Connect Node");
    m_manualConnectBtn->setStyleSheet("font-weight: bold; padding: 5px 10px;");

    manualLayout->addWidget(manualLabel);
    manualLayout->addWidget(m_manualIpEdit);
    manualLayout->addWidget(m_manualConnectBtn);

    connect(m_connectSelectedBtn, &QPushButton::clicked, this, &MainWindow::onConnectSelectedClicked);
    connect(m_connectAllBtn, &QPushButton::clicked, this, &MainWindow::onConnectAllClicked);
    connect(m_disconnectSelectedBtn, &QPushButton::clicked, this, &MainWindow::onDisconnectSelectedClicked);
    connect(m_manualConnectBtn, &QPushButton::clicked, this, &MainWindow::onManualConnectClicked);

    tableLayout->addWidget(m_nodesTable);
    tableLayout->addLayout(actionControlsLayout);
    tableLayout->addLayout(manualLayout);
    nodesSplitter->addWidget(rightTableWidget);
    nodesSplitter->setSizes(QList<int>() << 300 << 500);

    nodesLayout->addLayout(topNodesBar);
    nodesLayout->addWidget(boxRemoteHeader);
    nodesLayout->addWidget(nodesSplitter);

    m_topTabs->addTab(m_nodesPanel, "Discovered & Managed Nodes");

    QScrollArea* scrollArea = new QScrollArea(m_splitter);
    scrollArea->setWidgetResizable(true);
    
    m_thumbnailContainer = new QWidget();
    m_thumbnailLayout = new QGridLayout(m_thumbnailContainer);
    scrollArea->setWidget(m_thumbnailContainer);

    m_splitter->addWidget(m_topTabs);
    m_splitter->addWidget(scrollArea);
    
    QList<int> sizes;
    sizes << this->height() * 0.35 << this->height() * 0.65;
    m_splitter->setSizes(sizes);
    m_splitter->setStretchFactor(0, 0);
    m_splitter->setStretchFactor(1, 1);

    mainLayout->addWidget(m_splitter, 1);
    setCentralWidget(centralWidget);
}

void MainWindow::updateVoxAudioTrackList() {
    m_audioTrackListWidget->clear();
    for (const QString& ip : m_knownIps) {
        QListWidgetItem* item = new QListWidgetItem(QString("🎵 Android Audio Track [%1]").arg(ip), m_audioTrackListWidget);
        item->setData(Qt::UserRole, ip);
    }
}

void MainWindow::updateListWidget() {
    m_nodeListWidget->clear();
    m_nodesTable->setRowCount(0);
    int row = 0;
    for (const QString& ip : m_knownIps) {
        NodeInfo info = m_nodeInfoMap.value(ip);
        QString devName = info.deviceName.isEmpty() ? "Unknown Node" : info.deviceName;
        QString caps = info.capabilities.isEmpty() ? "audio,video" : info.capabilities;

        // Populate VOX style QListWidget
        QString displayText = QString("%1\nIP: %2 | Caps: %3")
                                  .arg(devName)
                                  .arg(ip)
                                  .arg(caps);
        QListWidgetItem *listWidgetHasItem = new QListWidgetItem(displayText, m_nodeListWidget);
        listWidgetHasItem->setData(Qt::UserRole, ip);
        listWidgetHasItem->setData(Qt::UserRole + 1, devName);

        // Populate Table Widget
        m_nodesTable->insertRow(row);
        bool isConnected = m_thumbnails.contains(ip) && m_thumbnails[ip]->isConnected;

        QTableWidgetItem* nameItem = new QTableWidgetItem(devName);
        QTableWidgetItem* ipItem = new QTableWidgetItem(ip);
        QTableWidgetItem* capsItem = new QTableWidgetItem(caps);
        
        QTableWidgetItem* statusItem = new QTableWidgetItem(isConnected ? "Connected" : "Idle");
        if (isConnected) {
            statusItem->setForeground(QBrush(QColor("#a6e3a1")));
        } else {
            statusItem->setForeground(QBrush(QColor("#6c7086")));
        }

        m_nodesTable->setItem(row, 0, nameItem);
        m_nodesTable->setItem(row, 1, ipItem);
        m_nodesTable->setItem(row, 2, capsItem);
        m_nodesTable->setItem(row, 3, statusItem);

        QWidget* btnWidget = new QWidget();
        QHBoxLayout* btnLayout = new QHBoxLayout(btnWidget);
        btnLayout->setContentsMargins(2, 2, 2, 2);
        
        QPushButton* connectSingleBtn = new QPushButton(isConnected ? "Disconnect" : "Connect");
        connectSingleBtn->setStyleSheet(isConnected ? "background-color: #f38ba8; color: #11111b; font-weight: bold; padding: 2px 8px; border-radius: 3px;" : "background-color: #a6e3a1; color: #11111b; font-weight: bold; padding: 2px 8px; border-radius: 3px;");
        
        connect(connectSingleBtn, &QPushButton::clicked, [this, ip, isConnected]() {
            if (isConnected) {
                disconnectNode(ip);
            } else {
                connectNode(ip);
            }
        });
        btnLayout->addWidget(connectSingleBtn);
        btnWidget->setLayout(btnLayout);

        m_nodesTable->setCellWidget(row, 4, btnWidget);
        row++;
    }
    updateVoxAudioTrackList();
}

void MainWindow::onNodeSelectionChanged() {
    QListWidgetItem *item = m_nodeListWidget->currentItem();
    if (!item) {
        m_nodeStatusLed->wht();
        m_lblSelectedNodeName->setText("No Node Selected");
        m_lblSelectedNodeIp->setText("IP: --.--.--.--");
        return;
    }

    QString ip = item->data(Qt::UserRole).toString();
    QString name = item->data(Qt::UserRole + 1).toString();

    bool isConnected = m_thumbnails.contains(ip) && m_thumbnails[ip]->isConnected;
    if (isConnected) {
        m_nodeStatusLed->grn();
    } else {
        m_nodeStatusLed->red();
    }
    m_lblSelectedNodeName->setText(name);
    m_lblSelectedNodeIp->setText(QString("IP: %1").arg(ip));
}

void MainWindow::onAudioTrackSelectionChanged() {
    QList<QListWidgetItem*> selectedItems = m_audioTrackListWidget->selectedItems();
    QSet<QString> selectedIps;
    QStringList activeNames;

    for (QListWidgetItem* item : selectedItems) {
        QString ip = item->data(Qt::UserRole).toString();
        selectedIps.insert(ip);
        activeNames.append(ip);
    }

    if (activeNames.isEmpty()) {
        m_activeTrackLabel->setText("Active Audio Track: None Selected");
    } else {
        m_activeTrackLabel->setText("Active Audio Track(s): " + activeNames.join(", "));
    }

    // Unmute selected tracks, mute unselected tracks
    for (auto it = m_thumbnails.begin(); it != m_thumbnails.end(); ++it) {
        const QString& ip = it.key();
        ThumbnailWidget* thumb = it.value();
        bool isSelected = selectedIps.contains(ip);
        thumb->setAudioMuted(!isSelected || m_masterMuteCb->isChecked());
        thumb->setAudioVolume(m_masterVolumeSlider->value());
    }
}

void MainWindow::onMasterVolumeChanged(int value) {
    QList<QListWidgetItem*> selectedItems = m_audioTrackListWidget->selectedItems();
    QSet<QString> selectedIps;
    for (QListWidgetItem* item : selectedItems) {
        selectedIps.insert(item->data(Qt::UserRole).toString());
    }

    for (auto it = m_thumbnails.begin(); it != m_thumbnails.end(); ++it) {
        if (selectedIps.contains(it.key())) {
            it.value()->setAudioVolume(value);
        }
    }
}

void MainWindow::onMasterMuteToggled(bool checked) {
    onAudioTrackSelectionChanged();
}

void MainWindow::loadIniFile() {
    QSettings settings(QDir::currentPath() + "/nodes.ini", QSettings::IniFormat);
    QStringList ips = settings.value("ips").toStringList();
    m_knownIps = QSet<QString>(ips.begin(), ips.end());
    updateListWidget();
    
    for (const QString& ip : m_knownIps) {
        createThumbnail(ip);
    }
}

void MainWindow::onSaveClicked() {
    QSettings settings(QDir::currentPath() + "/nodes.ini", QSettings::IniFormat);
    settings.setValue("ips", QStringList(m_knownIps.begin(), m_knownIps.end()));
    qDebug() << "Saved IPs to INI:" << m_knownIps;
}

void MainWindow::onResetSocketsClicked() {
    for (const QString& ip : m_knownIps) {
        m_discoveryService->sendReset(ip);
    }
    qDebug() << "Restarting sockets...";
    if (m_discoveryService) m_discoveryService->stop();
    if (m_opcUaServer) m_opcUaServer->stop();
    if (m_webSocketServer) m_webSocketServer->close();
    
    QTimer::singleShot(500, this, [this]() {
        setupSignalingServer();
        if (m_discoveryService) m_discoveryService->start();
        if (m_opcUaServer) m_opcUaServer->start();
        qDebug() << "Sockets restarted.";
    });
}

void MainWindow::onPlayClicked() {
    m_isPlaying = !m_isPlaying;
    if (m_isPlaying) {
        m_playBtn->setText("Stop");
        m_playBtn->setStyleSheet("background-color: red; color: white; font-weight: bold; padding: 5px;");
        for (ThumbnailWidget* thumb : m_thumbnails.values()) {
            if (!thumb->isConnected) {
                QString htmlPath = QDir::currentPath() + "/webrtc.html";
                if (!QFile::exists(htmlPath)) htmlPath = QDir::currentPath() + "/../webrtc.html";
                
                QFile htmlFile(htmlPath);
                if (htmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
                    QString htmlContent = htmlFile.readAll();
                    htmlContent.replace("ws.send(JSON.stringify({type: 'join', room: 'direct_room'}));", 
                                        QString("ws.send(JSON.stringify({type: 'join', room: '%1'}));").arg(thumb->ipAddress));
                    thumb->webView->setHtml(htmlContent, QUrl("http://localhost/"));
                }
                m_discoveryService->sendConnectRequest(thumb->ipAddress, thumb->rearCamCb->isChecked(), thumb->micCb->isChecked());
                thumb->isConnected = true;
            }
        }
    } else {
        m_playBtn->setText("Play");
        m_playBtn->setStyleSheet("background-color: green; color: white; font-weight: bold; padding: 5px;");
        for (ThumbnailWidget* thumb : m_thumbnails.values()) {
            thumb->webView->setHtml("");
            thumb->isConnected = false;
        }
        
        // Reset sockets completely for clean slate for next call
        onResetSocketsClicked();
    }
}

void MainWindow::onWatcherModeToggled(bool checked) {
    if (m_discoveryService) {
        m_discoveryService->setWatcherMode(checked);
    }
    if (checked) {
        m_watcherStatusLabel->setText("🛡 Mode: Watcher (Not Broadcasting IP)");
        m_watcherStatusLabel->setStyleSheet("font-weight: bold; color: #2e7d32; background: #e8f5e9; padding: 4px 8px; border-radius: 4px;");
    } else {
        m_watcherStatusLabel->setText("📡 Mode: Broadcaster (Broadcasting IP to Network)");
        m_watcherStatusLabel->setStyleSheet("font-weight: bold; color: #c62828; background: #ffebee; padding: 4px 8px; border-radius: 4px;");
    }
}

void MainWindow::connectNode(const QString& ip) {
    createThumbnail(ip);
    ThumbnailWidget* thumb = m_thumbnails.value(ip, nullptr);
    if (thumb && !thumb->isConnected) {
        QString htmlPath = QDir::currentPath() + "/webrtc.html";
        if (!QFile::exists(htmlPath)) htmlPath = QDir::currentPath() + "/../webrtc.html";
        
        QFile htmlFile(htmlPath);
        if (htmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QString htmlContent = htmlFile.readAll();
            htmlContent.replace("ws.send(JSON.stringify({type: 'join', room: 'direct_room'}));", 
                                QString("ws.send(JSON.stringify({type: 'join', room: '%1'}));").arg(ip));
            thumb->webView->setHtml(htmlContent, QUrl("http://localhost/"));
        }
        m_discoveryService->sendConnectRequest(ip, thumb->rearCamCb->isChecked(), thumb->micCb->isChecked());
        thumb->isConnected = true;
    }
    updateListWidget();
}

void MainWindow::disconnectNode(const QString& ip) {
    if (m_thumbnails.contains(ip)) {
        ThumbnailWidget* thumb = m_thumbnails[ip];
        if (thumb->isConnected) {
            thumb->webView->setHtml("");
            thumb->isConnected = false;
            m_discoveryService->sendReset(ip);
        }
    }
    updateListWidget();
}

void MainWindow::onConnectSelectedClicked() {
    QList<QTableWidgetItem*> selectedItems = m_nodesTable->selectedItems();
    QSet<int> selectedRows;
    for (QTableWidgetItem* item : selectedItems) {
        selectedRows.insert(item->row());
    }

    for (int r : selectedRows) {
        QTableWidgetItem* ipItem = m_nodesTable->item(r, 1);
        if (ipItem) {
            connectNode(ipItem->text());
        }
    }
}

void MainWindow::onConnectAllClicked() {
    for (const QString& ip : m_knownIps) {
        connectNode(ip);
    }
}

void MainWindow::onDisconnectSelectedClicked() {
    QList<QTableWidgetItem*> selectedItems = m_nodesTable->selectedItems();
    QSet<int> selectedRows;
    for (QTableWidgetItem* item : selectedItems) {
        selectedRows.insert(item->row());
    }

    for (int r : selectedRows) {
        QTableWidgetItem* ipItem = m_nodesTable->item(r, 1);
        if (ipItem) {
            disconnectNode(ipItem->text());
        }
    }
}

void MainWindow::onManualConnectClicked() {
    QString targetIp = m_manualIpEdit->text().trimmed();
    if (!targetIp.isEmpty()) {
        if (!m_knownIps.contains(targetIp)) {
            m_knownIps.insert(targetIp);
            NodeInfo info;
            info.deviceName = "Manual Node";
            info.ipAddress = targetIp;
            info.capabilities = "audio,video";
            m_nodeInfoMap[targetIp] = info;
        }
        connectNode(targetIp);
        m_manualIpEdit->clear();
    }
}

void MainWindow::onNodesUpdated(const QList<NodeInfo>& nodes) {
    bool updated = false;
    for (const NodeInfo& node : nodes) {
        m_nodeInfoMap[node.ipAddress] = node;
        if (!m_knownIps.contains(node.ipAddress)) {
            m_knownIps.insert(node.ipAddress);
            updated = true;
            qDebug() << "Discovered new node:" << node.ipAddress;
        }
    }
    updateListWidget();
}

void MainWindow::createThumbnail(const QString& ip) {
    if (m_thumbnails.contains(ip)) return;
    
    ThumbnailWidget* thumb = new ThumbnailWidget(ip, m_thumbnailContainer);
    connect(thumb, &ThumbnailWidget::deleteRequested, this, &MainWindow::onDeleteNode);
    connect(thumb, &ThumbnailWidget::flashToggled, this, [this](const QString& ip, bool enable) {
        QJsonObject msg;
        msg["type"] = "toggle_light";
        msg["enable"] = enable;
        m_discoveryService->sendSignalingMessage(ip, msg);
    });
    connect(thumb, &ThumbnailWidget::buzzerToggled, this, [this](const QString& ip, bool enable) {
        QJsonObject msg;
        msg["type"] = "toggle_buzzer";
        msg["enable"] = enable;
        m_discoveryService->sendSignalingMessage(ip, msg);
    });
    connect(thumb, &ThumbnailWidget::softResetRequested, this, [this](const QString& targetIp) {
        m_discoveryService->sendReset(targetIp);
    });
    
    connect(thumb->webView->page(), &QWebEnginePage::featurePermissionRequested,
            [thumb](const QUrl &securityOrigin, QWebEnginePage::Feature feature) {
        if (feature == QWebEnginePage::MediaAudioCapture || 
            feature == QWebEnginePage::MediaVideoCapture || 
            feature == QWebEnginePage::MediaAudioVideoCapture) {
            thumb->webView->page()->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
        }
    });

    m_thumbnails.insert(ip, thumb);
    
    QGridLayout* grid = qobject_cast<QGridLayout*>(m_thumbnailLayout);
    int count = grid->count();
    int row = count / 3;
    int col = count % 3;
    grid->addWidget(thumb, row, col);
    
    // If we are currently playing, automatically connect the new node
    if (m_isPlaying) {
        QString htmlPath = QDir::currentPath() + "/webrtc.html";
        if (!QFile::exists(htmlPath)) htmlPath = QDir::currentPath() + "/../webrtc.html";
        
        QFile htmlFile(htmlPath);
        if (htmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QString htmlContent = htmlFile.readAll();
            htmlContent.replace("ws.send(JSON.stringify({type: 'join', room: 'direct_room'}));", 
                                QString("ws.send(JSON.stringify({type: 'join', room: '%1'}));").arg(ip));
            thumb->webView->setHtml(htmlContent, QUrl("http://localhost/"));
        }
        m_discoveryService->sendConnectRequest(ip, thumb->rearCamCb->isChecked(), thumb->micCb->isChecked());
        thumb->isConnected = true;
    }
}

void MainWindow::onDeleteNode(const QString& ip) {
    if (m_thumbnails.contains(ip)) {
        ThumbnailWidget* thumb = m_thumbnails.take(ip);
        m_thumbnailLayout->removeWidget(thumb);
        thumb->deleteLater();
    }
    m_knownIps.remove(ip);
    updateListWidget();
    
    QGridLayout* grid = qobject_cast<QGridLayout*>(m_thumbnailLayout);
    int idx = 0;
    for (ThumbnailWidget* w : m_thumbnails.values()) {
        grid->removeWidget(w);
        grid->addWidget(w, idx / 3, idx % 3);
        idx++;
    }
}

void MainWindow::setupSignalingServer() {
    m_webSocketServer = new QWebSocketServer(QStringLiteral("Signaling Server"),
                                             QWebSocketServer::NonSecureMode, this);
    if (m_webSocketServer->listen(QHostAddress::Any, 8765)) {
        connect(m_webSocketServer, &QWebSocketServer::newConnection,
                this, &MainWindow::onNewWebSocketConnection);
    }
}

void MainWindow::onNewWebSocketConnection() {
    QWebSocket *client = m_webSocketServer->nextPendingConnection();
    connect(client, &QWebSocket::textMessageReceived, this, &MainWindow::onWebSocketMessageReceived);
    connect(client, &QWebSocket::disconnected, this, &MainWindow::onWebSocketDisconnected);
    m_clients << client;
}

void MainWindow::onWebSocketMessageReceived(const QString &message) {
    QWebSocket *client = qobject_cast<QWebSocket *>(sender());
    if (!client) return;

    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
    if (!doc.isObject()) return;

    QJsonObject msg = doc.object();
    QString type = msg["type"].toString();

    if (type == "join") {
        QString targetIp = msg["room"].toString();
        client->setProperty("target_ip", targetIp);
        
        QJsonObject reply;
        reply["type"] = "joined";
        reply["peer_id"] = "local";
        sendSignalingMessage(client, reply);

        QJsonObject cmd;
        cmd["type"] = "initiate_call";
        sendSignalingMessage(client, cmd);
    }
    else if (type == "offer" || type == "answer" || type == "ice_candidate") {
        QString targetIp = client->property("target_ip").toString();
        if (!targetIp.isEmpty()) {
            QJsonObject udpMsg = msg;
            udpMsg["from"] = "remote"; 
            m_discoveryService->sendSignalingMessage(targetIp, udpMsg);
        }
    }
}

void MainWindow::onUdpSignalingMessageReceived(const QString& senderIp, const QJsonObject& msg) {
    QJsonObject localMsg = msg;
    localMsg["from"] = "remote";
    
    for (QWebSocket* p : m_clients) {
        if (p->property("target_ip").toString() == senderIp) {
            sendSignalingMessage(p, localMsg);
            break;
        }
    }
}

void MainWindow::onWebSocketDisconnected() {
    QWebSocket *client = qobject_cast<QWebSocket *>(sender());
    if (client) {
        m_clients.removeAll(client);
        client->deleteLater();
    }
}

void MainWindow::broadcastSignalingMessage(const QJsonObject& msg, QWebSocket* exclude) {
    for (QWebSocket* p : m_clients) {
        if (p != exclude) {
            sendSignalingMessage(p, msg);
        }
    }
}

void MainWindow::sendSignalingMessage(QWebSocket* client, const QJsonObject& msg) {
    client->sendTextMessage(QJsonDocument(msg).toJson(QJsonDocument::Compact));
}

void MainWindow::setupDarkStyle() {
    qApp->setStyle("Fusion");

    QPalette darkPalette;
    darkPalette.setColor(QPalette::Window, QColor(30, 30, 46));
    darkPalette.setColor(QPalette::WindowText, QColor(205, 214, 244));
    darkPalette.setColor(QPalette::Base, QColor(24, 24, 37));
    darkPalette.setColor(QPalette::AlternateBase, QColor(30, 30, 46));
    darkPalette.setColor(QPalette::ToolTipBase, QColor(205, 214, 244));
    darkPalette.setColor(QPalette::ToolTipText, QColor(205, 214, 244));
    darkPalette.setColor(QPalette::Text, QColor(205, 214, 244));
    darkPalette.setColor(QPalette::Button, QColor(49, 50, 68));
    darkPalette.setColor(QPalette::ButtonText, QColor(205, 214, 244));
    darkPalette.setColor(QPalette::BrightText, Qt::red);
    darkPalette.setColor(QPalette::Link, QColor(137, 180, 250));
    darkPalette.setColor(QPalette::Highlight, QColor(137, 180, 250));
    darkPalette.setColor(QPalette::HighlightedText, QColor(17, 17, 27));

    qApp->setPalette(darkPalette);
}
