#include "session.h"
#include "server.h"
#include <iostream>

namespace scar {

Session::Session(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket,
                 std::shared_ptr<Authenticator> auth,
                 Server* server)
    : socket_(std::move(socket)), auth_(auth), server_(server), authenticated_(false) {}

void Session::start() {
    doHandshake();
}

void Session::doHandshake() {
    auto self(shared_from_this());
    socket_.async_handshake(boost::asio::ssl::stream_base::server,
        [this, self](const boost::system::error_code& error) {
            if (!error) {
                std::cout << "SSL handshake completed" << std::endl;
                doReadHeader();
            } else {
                std::cerr << "SSL handshake error: " << error.message() << std::endl;
            }
        });
}

void Session::doReadHeader() {
    read_buffer_.resize(sizeof(MessageHeader));
    
    auto self(shared_from_this());
    boost::asio::async_read(socket_,
        boost::asio::buffer(read_buffer_),
        [this, self](const boost::system::error_code& error, std::size_t /*length*/) {
            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;
                if (authenticated_) {
                    server_->removeSession(shared_from_this());
                }
            }
        });
}

void Session::doReadBody(uint32_t length) {
    auto body_buffer = std::make_shared<std::vector<uint8_t>>(length);
    
    auto self(shared_from_this());
    boost::asio::async_read(socket_,
        boost::asio::buffer(*body_buffer),
        [this, self, body_buffer](const boost::system::error_code& error, std::size_t /*bytes*/) {
            if (!error) {
                // Combine header and body
                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 deserialization error: " << e.what() << std::endl;
                }
                
                doReadHeader();
            } else {
                std::cerr << "Read error: " << error.message() << std::endl;
                if (authenticated_) {
                    server_->removeSession(shared_from_this());
                }
            }
        });
}

void Session::handleMessage(std::unique_ptr<Message> message) {
    std::cout << "Received message type: " << static_cast<int>(message->type()) << std::endl;
    
    switch (message->type()) {
        case MessageType::LOGIN_REQUEST:
            handleLoginRequest(*dynamic_cast<LoginRequest*>(message.get()));
            break;
            
        case MessageType::TEXT_MESSAGE:
            if (authenticated_) {
                server_->broadcastMessage(*dynamic_cast<TextMessage*>(message.get()));
            }
            break;
        
        case MessageType::SCREEN_SHARE_START:
        case MessageType::SCREEN_SHARE_DATA:
        case MessageType::SCREEN_SHARE_STOP:
            if (authenticated_) {
                // Broadcast screen share messages to all other clients
                server_->broadcastToOthers(*message, shared_from_this());
            }
            break;
            
        default:
            std::cerr << "Unhandled message type" << std::endl;
            break;
    }
}

void Session::handleLoginRequest(const LoginRequest& request) {
    std::cout << "LoginRequest received - Username: '" << request.username() 
              << "', Password length: " << request.password().length() << std::endl;
    
    std::string token = auth_->authenticate(request.username(), request.password());
    
    if (!token.empty()) {
        authenticated_ = true;
        username_ = request.username();
        
        LoginResponse response(true, token);
        std::cout << "Sending successful LoginResponse with token" << std::endl;
        send(response);
        
        server_->addSession(shared_from_this());
    } else {
        LoginResponse response(false, "", ErrorCode::AUTH_FAILED);
        std::cout << "Sending failed LoginResponse" << std::endl;
        send(response);
    }
}

void Session::send(const Message& message) {
    auto self(shared_from_this());
    write_buffer_ = message.serialize();
    
    std::cout << "Sending message type " << static_cast<int>(message.type()) 
              << ", size: " << write_buffer_.size() << " bytes" << std::endl;
    
    boost::asio::async_write(socket_,
        boost::asio::buffer(write_buffer_),
        [this, self](const boost::system::error_code& error, std::size_t bytes) {
            if (error) {
                std::cerr << "Write error: " << error.message() << std::endl;
                if (authenticated_) {
                    server_->removeSession(shared_from_this());
                }
            } else {
                std::cout << "Successfully sent " << bytes << " bytes" << std::endl;
            }
        });
}

} // namespace scar
