#include "client_connection.h"
#include <QTimer>
#include <thread>
#include <iostream>

namespace scar {

ClientConnection::ClientConnection(QObject* parent)
    : QObject(parent),
      connected_(false),
      should_reconnect_(false),
      reconnect_attempts_(0),
      backoff_delay_(std::chrono::seconds(INITIAL_BACKOFF_SECONDS)) {
    
    io_context_ = std::make_unique<boost::asio::io_context>();
    ssl_context_ = std::make_unique<boost::asio::ssl::context>(
        boost::asio::ssl::context::tlsv12_client
    );
    
    ssl_context_->set_verify_mode(boost::asio::ssl::verify_none); // TODO: Proper cert verification
}

ClientConnection::~ClientConnection() {
    disconnect();
}

void ClientConnection::connectToServer(const std::string& host, uint16_t port,
                                      const std::string& username, const std::string& password) {
    last_host_ = host;
    last_port_ = port;
    last_username_ = username;
    last_password_ = password;
    should_reconnect_ = true;
    reconnect_attempts_ = 0;
    
    doConnect(host, port);
    
    // Run io_context in separate thread
    std::thread([this]() { runIoContext(); }).detach();
}

void ClientConnection::disconnect() {
    should_reconnect_ = false;
    connected_ = false;
    
    if (socket_) {
        boost::system::error_code ec;
        socket_->lowest_layer().close(ec);
    }
    
    if (io_context_) {
        io_context_->stop();
    }
    
    emit disconnected();
}

void ClientConnection::doConnect(const std::string& host, uint16_t port) {
    io_context_->restart();
    work_guard_ = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(
        io_context_->get_executor()
    );
    
    socket_ = std::make_unique<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(
        *io_context_, *ssl_context_
    );
    
    boost::asio::ip::tcp::resolver resolver(*io_context_);
    auto endpoints = resolver.resolve(host, std::to_string(port));
    
    boost::asio::async_connect(socket_->lowest_layer(), endpoints,
        [this](const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint&) {
            if (!error) {
                std::cout << "Connected to server" << std::endl;
                doHandshake();
            } else {
                std::cerr << "Connection error: " << error.message() << std::endl;
                emit connectionError(QString::fromStdString(error.message()));
                scheduleReconnect();
            }
        });
}

void ClientConnection::doHandshake() {
    socket_->async_handshake(boost::asio::ssl::stream_base::client,
        [this](const boost::system::error_code& error) {
            if (!error) {
                std::cout << "SSL handshake completed" << std::endl;
                connected_ = true;
                reconnect_attempts_ = 0;
                backoff_delay_ = std::chrono::seconds(INITIAL_BACKOFF_SECONDS);
                emit connected();
                doLogin(last_username_, last_password_);
                doReadHeader();
            } else {
                std::cerr << "SSL handshake error: " << error.message() << std::endl;
                emit connectionError(QString::fromStdString(error.message()));
                scheduleReconnect();
            }
        });
}

void ClientConnection::doLogin(const std::string& username, const std::string& password) {
    std::cout << "doLogin called - Username: '" << username << "', Password length: " << password.length() << std::endl;
    
    LoginRequest request(username, password);
    auto data = request.serialize();
    
    std::cout << "Sending LoginRequest, data size: " << data.size() << std::endl;
    
    boost::asio::async_write(*socket_,
        boost::asio::buffer(data),
        [this](const boost::system::error_code& error, std::size_t) {
            if (error) {
                std::cerr << "Login send error: " << error.message() << std::endl;
                emit connectionError(QString::fromStdString(error.message()));
            } else {
                std::cout << "LoginRequest sent successfully" << std::endl;
            }
        });
}

void ClientConnection::doReadHeader() {
    read_buffer_.resize(sizeof(MessageHeader));
    
    boost::asio::async_read(*socket_,
        boost::asio::buffer(read_buffer_),
        [this](const boost::system::error_code& error, std::size_t) {
            if (!error) {
                MessageHeader header;
                std::memcpy(&header, read_buffer_.data(), sizeof(MessageHeader));
                
                if (header.length > sizeof(MessageHeader)) {
                    doReadBody(header.length - sizeof(MessageHeader));
                } else {
                    doReadHeader();
                }
            } else {
                std::cerr << "Read error: " << error.message() << std::endl;
                connected_ = false;
                emit disconnected();
                scheduleReconnect();
            }
        });
}

void ClientConnection::doReadBody(uint32_t length) {
    auto body_buffer = std::make_shared<std::vector<uint8_t>>(length);
    
    boost::asio::async_read(*socket_,
        boost::asio::buffer(*body_buffer),
        [this, body_buffer](const boost::system::error_code& error, std::size_t) {
            if (!error) {
                std::vector<uint8_t> full_message;
                full_message.insert(full_message.end(), read_buffer_.begin(), read_buffer_.end());
                full_message.insert(full_message.end(), body_buffer->begin(), body_buffer->end());
                
                try {
                    auto message = Message::deserialize(full_message);
                    handleMessage(std::move(message));
                } catch (const std::exception& e) {
                    std::cerr << "Message error: " << e.what() << std::endl;
                }
                
                doReadHeader();
            } else {
                std::cerr << "Read body error: " << error.message() << std::endl;
                connected_ = false;
                emit disconnected();
                scheduleReconnect();
            }
        });
}

void ClientConnection::handleMessage(std::unique_ptr<Message> message) {
    std::cout << "Client received message type: " << static_cast<int>(message->type()) << std::endl;
    
    switch (message->type()) {
        case MessageType::LOGIN_RESPONSE: {
            auto* response = dynamic_cast<LoginResponse*>(message.get());
            std::cout << "LoginResponse - Success: " << response->success() << std::endl;
            if (response->success()) {
                std::cout << "Login successful, token received" << std::endl;
                emit loginSuccess(QString::fromStdString(response->token()));
            } else {
                std::cout << "Login failed" << std::endl;
                emit loginFailed("Authentication failed");
            }
            break;
        }
        
        case MessageType::TEXT_MESSAGE: {
            auto* text_msg = dynamic_cast<TextMessage*>(message.get());
            emit messageReceived(
                QString::fromStdString(text_msg->sender()),
                QString::fromStdString(text_msg->content())
            );
            break;
        }
        
        case MessageType::SCREEN_SHARE_START: {
            auto* start_msg = dynamic_cast<ScreenShareStart*>(message.get());
            std::cout << "ScreenShareStart received - Width: " << start_msg->width() 
                      << " Height: " << start_msg->height() << std::endl;
            if (!screen_share_decoder_) {
                screen_share_decoder_ = std::make_unique<VideoDecoder>();
                if (!screen_share_decoder_->initialize()) {
                    std::cerr << "Failed to initialize video decoder" << std::endl;
                    screen_share_decoder_.reset();
                }
            }
            break;
        }
        
        case MessageType::SCREEN_SHARE_DATA: {
            auto* data_msg = dynamic_cast<ScreenShareData*>(message.get());
            if (screen_share_decoder_) {
                int width = 0, height = 0;
                std::cout << "About to call decode..." << std::endl;
                std::vector<uint8_t> rgbData = screen_share_decoder_->decode(data_msg->frameData(), width, height);
                std::cout << "Decode returned, rgbData.size()=" << rgbData.size() << std::endl;
                if (!rgbData.empty()) {
                    std::cout << "About to emit signal..." << std::endl;
                    emit screenShareFrameReceived(rgbData, width, height);
                    std::cout << "Signal emitted successfully" << std::endl;
                }
            } else {
                std::cerr << "Received screen share data but decoder not initialized" << std::endl;
            }
            break;
        }
        
        case MessageType::SCREEN_SHARE_STOP: {
            std::cout << "ScreenShareStop received" << std::endl;
            if (screen_share_decoder_) {
                screen_share_decoder_->cleanup();
                screen_share_decoder_.reset();
            }
            break;
        }
        
        default:
            break;
    }
}

void ClientConnection::sendTextMessage(const std::string& content) {
    if (!connected_) return;
    
    TextMessage message(last_username_, content);
    auto data = message.serialize();
    
    boost::asio::async_write(*socket_,
        boost::asio::buffer(data),
        [](const boost::system::error_code& error, std::size_t) {
            if (error) {
                std::cerr << "Send error: " << error.message() << std::endl;
            }
        });
}

void ClientConnection::sendData(const std::vector<uint8_t>& data) {
    if (!connected_) return;
    
    boost::asio::async_write(*socket_,
        boost::asio::buffer(data),
        [](const boost::system::error_code& error, std::size_t bytes) {
            if (error) {
                std::cerr << "Send error: " << error.message() << std::endl;
            }
        });
}

void ClientConnection::scheduleReconnect() {
    if (!should_reconnect_ || reconnect_attempts_ >= MAX_RECONNECT_ATTEMPTS) {
        emit connectionError("Max reconnection attempts reached");
        return;
    }
    
    reconnect_attempts_++;
    
    std::cout << "Reconnecting in " << backoff_delay_.count() << " seconds (attempt " 
              << reconnect_attempts_ << "/" << MAX_RECONNECT_ATTEMPTS << ")" << std::endl;
    
    QTimer::singleShot(backoff_delay_.count() * 1000, [this]() {
        doConnect(last_host_, last_port_);
    });
    
    // Exponential backoff
    backoff_delay_ = std::min(
        backoff_delay_ * 2,
        std::chrono::seconds(MAX_BACKOFF_SECONDS)
    );
}

void ClientConnection::runIoContext() {
    try {
        io_context_->run();
    } catch (const std::exception& e) {
        std::cerr << "IO context error: " << e.what() << std::endl;
    }
}

} // namespace scar
