#include "video_grid_widget.h"
#include "../media/screen_capture.h"
#include "../connection/client_connection.h"
#include "../../shared/protocol/message.h"
#include <QFrame>
#include <QResizeEvent>
#include <algorithm>
#include <cmath>
#include <iostream>

namespace scar {

VideoGridWidget::VideoGridWidget(QWidget* parent)
    : QWidget(parent),
      isScreenSharing_(false),
      screenShareStartSent_(false),
      connection_(nullptr),
      processingFrame_(false) {
    
    gridLayout_ = new QGridLayout(this);
    gridLayout_->setSpacing(5);
    gridLayout_->setContentsMargins(5, 5, 5, 5);
    
    // Placeholder when no streams
    placeholderLabel_ = new QLabel("No active video streams", this);
    placeholderLabel_->setAlignment(Qt::AlignCenter);
    placeholderLabel_->setStyleSheet("color: #888; font-size: 16px;");
    gridLayout_->addWidget(placeholderLabel_, 0, 0);
    
    // Create screen share button (floating above video streams)
    screenShareButton_ = new QPushButton("Share Screen", this);
    screenShareButton_->setStyleSheet(
        "QPushButton {"
        "  background-color: #5865F2;"
        "  color: white;"
        "  border: none;"
        "  border-radius: 8px;"
        "  padding: 12px 24px;"
        "  font-size: 14px;"
        "  font-weight: bold;"
        "}"
        "QPushButton:hover {"
        "  background-color: #4752C4;"
        "}"
        "QPushButton:pressed {"
        "  background-color: #3C45A5;"
        "}"
        "QPushButton:disabled {"
        "  background-color: #4F545C;"
        "  color: #72767D;"
        "}"
    );
    screenShareButton_->setCursor(Qt::PointingHandCursor);
    screenShareButton_->setFixedSize(160, 48);
    screenShareButton_->raise(); // Ensure button is above other widgets
    
    connect(screenShareButton_, &QPushButton::clicked, this, &VideoGridWidget::onScreenShareClicked);
    
    // Initialize screen capture
    screenCapture_ = new ScreenCapture();
    
    updateScreenShareButtonPosition();
}

VideoGridWidget::~VideoGridWidget() {
    delete screenCapture_;
}

void VideoGridWidget::setConnection(ClientConnection* connection) {
    connection_ = connection;
    
    // Set up frame callback for screen capture
    if (screenCapture_) {
        screenCapture_->setFrameCallback([this](const std::vector<uint8_t>& frameData, int width, int height) {
            if (!connection_) {
                return;
            }
            
            try {
                // Send ScreenShareStart with actual dimensions on first frame
                if (!screenShareStartSent_) {
                    ScreenShareStart startMsg(width, height);
                    auto startSerialized = startMsg.serialize();
                    connection_->sendData(startSerialized);
                    std::cout << "Sent ScreenShareStart with actual dimensions: " << width << "x" << height << std::endl;
                    screenShareStartSent_ = true;
                }
                
                static int callback_count = 0;
                if (++callback_count % 30 == 0) {
                    std::cout << "Sending screen share frame: " << callback_count 
                             << " Size: " << frameData.size() << " bytes"
                             << " Resolution: " << width << "x" << height << std::endl;
                }
                
                // frameData is already H.264 encoded by ScreenCapture
                // Send it directly to server
                ScreenShareData frameMsg(frameData);
                auto serialized = frameMsg.serialize();
                connection_->sendData(serialized);
            } catch (const std::exception& e) {
                std::cerr << "Error in frame callback: " << e.what() << std::endl;
            } catch (...) {
                std::cerr << "Unknown error in frame callback" << std::endl;
            }
        });
    }
}

void VideoGridWidget::addStream(const QString& streamId, const QString& username) {
    if (streams_.size() >= MAX_STREAMS) {
        return; // Max streams reached
    }
    
    // Remove placeholder if this is first stream
    if (streams_.empty()) {
        placeholderLabel_->hide();
    }
    
    VideoStream stream;
    stream.streamId = streamId;
    stream.username = username;
    
    // Create video label
    stream.videoLabel = new QLabel(this);
    stream.videoLabel->setMinimumSize(160, 120);
    stream.videoLabel->setStyleSheet("QLabel { background-color: #2C2F33; border: 1px solid #23272A; }");
    stream.videoLabel->setScaledContents(true);
    stream.videoLabel->setAlignment(Qt::AlignCenter);
    stream.videoLabel->setText(username + "\n(No video)");
    stream.videoLabel->setToolTip(username);
    
    streams_.push_back(stream);
    updateGridLayout();
}

void VideoGridWidget::removeStream(const QString& streamId) {
    for (auto it = streams_.begin(); it != streams_.end(); ++it) {
        if (it->streamId == streamId) {
            delete it->videoLabel;
            streams_.erase(it);
            break;
        }
    }
    
    if (streams_.empty()) {
        placeholderLabel_->show();
    } else {
        updateGridLayout();
    }
}

void VideoGridWidget::updateFrame(const QString& streamId, const QPixmap& frame) {
    for (auto& stream : streams_) {
        if (stream.streamId == streamId) {
            stream.videoLabel->setPixmap(frame);
            break;
        }
    }
}

void VideoGridWidget::clear() {
    for (auto& stream : streams_) {
        delete stream.videoLabel;
    }
    streams_.clear();
    placeholderLabel_->show();
}

void VideoGridWidget::updateGridLayout() {
    // Remove all widgets from layout
    for (auto& stream : streams_) {
        gridLayout_->removeWidget(stream.videoLabel);
    }
    
    int columns = calculateColumns(streams_.size());
    int rows = std::ceil(static_cast<double>(streams_.size()) / columns);
    
    // Re-add widgets in grid
    for (size_t i = 0; i < streams_.size(); ++i) {
        int row = i / columns;
        int col = i % columns;
        gridLayout_->addWidget(streams_[i].videoLabel, row, col);
    }
}

int VideoGridWidget::calculateColumns(int streamCount) {
    if (streamCount <= 1) return 1;
    if (streamCount <= 4) return 2;
    if (streamCount <= 9) return 3;
    if (streamCount <= 16) return 4;
    if (streamCount <= 25) return 5;
    if (streamCount <= 36) return 6;
    return std::ceil(std::sqrt(streamCount));
}

void VideoGridWidget::onScreenShareClicked() {
    if (isScreenSharing_) {
        // Stop screen sharing
        screenCapture_->stop();
        isScreenSharing_ = false;
            screenShareButton_->setText("Share Screen");
            screenShareButton_->setStyleSheet(
                "QPushButton {"
                "  background-color: #5865F2;"
                "  color: white;"
                "  border: none;"
                "  border-radius: 8px;"
                "  padding: 12px 24px;"
                "  font-size: 14px;"
                "  font-weight: bold;"
                "}"
                "QPushButton:hover {"
                "  background-color: #4752C4;"
                "}"
                "QPushButton:pressed {"
                "  background-color: #3C45A5;"
                "}"
            );
            
            screenShareStartSent_ = false;        // Send stop message
        if (connection_) {
            ScreenShareStop stopMsg;
            auto serialized = stopMsg.serialize();
            connection_->sendData(serialized);
            qDebug() << "Sent screen share stop message";
        }
    } else {
        // Start screen sharing - this will open xdg-desktop-portal dialog
        if (screenCapture_->start()) {
            isScreenSharing_ = true;
            screenShareButton_->setText("Stop Sharing");
            screenShareButton_->setStyleSheet(
                "QPushButton {"
                "  background-color: #ED4245;"
                "  color: white;"
                "  border: none;"
                "  border-radius: 8px;"
                "  padding: 12px 24px;"
                "  font-size: 14px;"
                "  font-weight: bold;"
                "}"
                "QPushButton:hover {"
                "  background-color: #C03537;"
                "}"
                "QPushButton:pressed {"
                "  background-color: #A12D2F;"
                "}"
            );
            
            // ScreenShareStart will be sent with actual dimensions when first frame arrives
            emit screenShareRequested();
        }
    }
}

void VideoGridWidget::onScreenShareFrameReceived(std::shared_ptr<std::vector<uint8_t>> rgbData, int width, int height, int linesize) {
    static int frame_count = 0;
    static int dropped_frames = 0;
    ++frame_count;
    
    // Drop frame if we're still processing the previous one
    bool expected = false;
    if (!processingFrame_.compare_exchange_strong(expected, true)) {
        ++dropped_frames;
        if (dropped_frames % 10 == 1) {
            std::cout << "Dropped frame " << frame_count << " (total dropped: " << dropped_frames 
                      << ") - still processing previous frame" << std::endl;
        }
        return;
    }
    
    // RAII guard to ensure we always clear the processing flag
    struct FrameGuard {
        std::atomic<bool>& flag;
        ~FrameGuard() { flag = false; }
    } guard{processingFrame_};
    
    std::cout << "=== onScreenShareFrameReceived START frame #" << frame_count 
              << ": size=" << rgbData->size() 
              << ", " << width << "x" << height << ", linesize=" << linesize << " ===" << std::endl;
    
    if (rgbData->empty()) {
        std::cerr << "Empty rgbData, returning" << std::endl;
        return;
    }
    
    // Validate buffer size BEFORE doing anything
    size_t expected_size = static_cast<size_t>(linesize) * height;
    if (rgbData->size() < expected_size) {
        std::cerr << "Buffer too small: " << rgbData->size() << " < " << expected_size << std::endl;
        return;
    }
    
    std::cout << "Creating QImage wrapper (no allocation) for frame " << frame_count << std::endl;
    
    // CRITICAL: Use QImage constructor that wraps external buffer (NO COPY)
    // QImage does NOT take ownership - it just references our data
    // We need to ensure rgbData stays alive until QPixmap copies it
    QImage tempImage(rgbData->data(), width, height, linesize, QImage::Format_RGB888);
    
    if (tempImage.isNull()) {
        std::cerr << "Failed to create QImage wrapper" << std::endl;
        return;
    }
    
    // No manual copy needed - tempImage wraps rgbData directly (zero-copy)
    // QImage will use our linesize, no mismatch issues
    std::cout << "QImage wrapper verified, buffer size=" << rgbData->size() 
              << ", linesize=" << linesize << std::endl;
    
    // Create a stream if this is the first frame from a remote screen share
    // Use a special stream ID for remote screen shares
    const QString remoteStreamId = "remote_screen_share";
    
    // Find existing stream or create new one
    auto it = std::find_if(streams_.begin(), streams_.end(),
        [&remoteStreamId](const VideoStream& s) { return s.streamId == remoteStreamId; });
    
    if (it == streams_.end()) {
        std::cout << "Creating new stream for remote screen share..." << std::endl;
        // Create new stream for remote screen share
        addStream(remoteStreamId, "Screen Share");
        std::cout << "Stream created, finding it..." << std::endl;
        it = std::find_if(streams_.begin(), streams_.end(),
            [&remoteStreamId](const VideoStream& s) { return s.streamId == remoteStreamId; });
    }
    
    std::cout << "About to convert QImage to QPixmap..." << std::endl;
    
    if (it != streams_.end() && it->videoLabel) {
        std::cout << "Converting to QPixmap (this will make a deep copy)..." << std::endl;
        // QPixmap::fromImage makes its own deep copy - after this, rgbData can be released
        QPixmap pixmap = QPixmap::fromImage(tempImage);
        
        std::cout << "QPixmap created, use_count=" << rgbData.use_count() << std::endl;
        
        // CRITICAL: Explicitly destroy tempImage BEFORE rgbData goes out of scope
        // to prevent QImage from holding dangling pointer during destruction
        tempImage = QImage();  // Assign empty QImage to release reference
        
        std::cout << "tempImage cleared, use_count=" << rgbData.use_count() << std::endl;
        
        if (pixmap.isNull()) {
            std::cerr << "Failed to create QPixmap from QImage" << std::endl;
            return;
        }
        
        std::cout << "QPixmap valid, about to scale..." << std::endl;
        
        // Scale to fit the label - this creates another copy
        QPixmap scaled = pixmap.scaled(it->videoLabel->size(), 
                                       Qt::KeepAspectRatio, 
                                       Qt::SmoothTransformation);
        
        std::cout << "Scaled pixmap created, about to set on label..." << std::endl;
        
        // Set the pixmap - QLabel makes its own copy internally
        it->videoLabel->setPixmap(scaled);
        
        std::cout << "Pixmap set on label" << std::endl;
        
        if (frame_count == 1 || frame_count % 30 == 0) {
            std::cout << "Frame " << frame_count << " displayed successfully" << std::endl;
        }
    }
    
    std::cout << "Function complete, rgbData going out of scope, use_count=" 
              << rgbData.use_count() << std::endl;
    
    // rgbData will be destroyed when all references are gone
    // tempImage was explicitly cleared above
}

void VideoGridWidget::resizeEvent(QResizeEvent* event) {
    QWidget::resizeEvent(event);
    updateScreenShareButtonPosition();
}

void VideoGridWidget::updateScreenShareButtonPosition() {
    // Position button at bottom center of the widget
    int buttonWidth = screenShareButton_->width();
    int buttonHeight = screenShareButton_->height();
    int x = (width() - buttonWidth) / 2;
    int y = height() - buttonHeight - 20; // 20px margin from bottom
    
    screenShareButton_->move(x, y);
}

} // namespace scar
