#include "SocketWrapper.h"
#include <iostream>
#include <cstring>

SocketWrapper::SocketWrapper() 
    : m_socket(INVALID_SOCKET_FD), m_isValid(false) {
}

SocketWrapper::SocketWrapper(SocketFd socket) 
    : m_socket(socket), m_isValid(socket != INVALID_SOCKET_FD) {
}

SocketWrapper::~SocketWrapper() {
    close();
}

bool SocketWrapper::initializeWinsock() {
#ifdef _WIN32
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        std::cerr << "WSAStartup failed: " << result << std::endl;
        return false;
    }
#endif
    return true;
}

void SocketWrapper::cleanupWinsock() {
#ifdef _WIN32
    WSACleanup();
#endif
}

bool SocketWrapper::create() {
    m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (m_socket == INVALID_SOCKET_FD) {
        std::cerr << "Socket creation failed: " << getLastError() << std::endl;
        return false;
    }
    m_isValid = true;
    return true;
}

bool SocketWrapper::bind(const std::string& address, int port) {
    if (!m_isValid) return false;
    
    sockaddr_in serverAddr;
    std::memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    
    if (address == "0.0.0.0" || address.empty()) {
        serverAddr.sin_addr.s_addr = INADDR_ANY;
    } else {
        inet_pton(AF_INET, address.c_str(), &serverAddr.sin_addr);
    }
    
    if (::bind(m_socket, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        std::cerr << "Bind failed: " << getLastError() << std::endl;
        return false;
    }
    
    return true;
}

bool SocketWrapper::listen(int backlog) {
    if (!m_isValid) return false;
    
    if (::listen(m_socket, backlog) < 0) {
        std::cerr << "Listen failed: " << getLastError() << std::endl;
        return false;
    }
    
    return true;
}

SocketFd SocketWrapper::accept(std::string& clientAddress, int& clientPort) {
    if (!m_isValid) return INVALID_SOCKET_FD;
    
    sockaddr_in clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    
    SocketFd clientSocket = ::accept(m_socket, (sockaddr*)&clientAddr, &clientAddrLen);
    if (clientSocket == INVALID_SOCKET_FD) {
        return INVALID_SOCKET_FD;
    }
    
    char addrStr[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &clientAddr.sin_addr, addrStr, INET_ADDRSTRLEN);
    clientAddress = addrStr;
    clientPort = ntohs(clientAddr.sin_port);
    
    return clientSocket;
}

bool SocketWrapper::connect(const std::string& address, int port) {
    if (!m_isValid) return false;
    
    sockaddr_in serverAddr;
    std::memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    inet_pton(AF_INET, address.c_str(), &serverAddr.sin_addr);
    
    if (::connect(m_socket, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        std::cerr << "Connect failed: " << getLastError() << std::endl;
        return false;
    }
    
    return true;
}

int SocketWrapper::send(const char* data, int length) {
    if (!m_isValid) return -1;
    
    int result = ::send(m_socket, data, length, 0);
    if (result < 0) {
        std::cerr << "Send failed: " << getLastError() << std::endl;
    }
    return result;
}

int SocketWrapper::send(const std::string& message) {
    return send(message.c_str(), static_cast<int>(message.length()));
}

int SocketWrapper::recv(char* buffer, int length) {
    if (!m_isValid) return -1;
    
    int result = ::recv(m_socket, buffer, length, 0);
    if (result < 0) {
        std::cerr << "Recv failed: " << getLastError() << std::endl;
    }
    return result;
}

std::string SocketWrapper::recvLine() {
    std::string line;
    char ch;
    
    while (true) {
        int result = recv(&ch, 1);
        if (result <= 0) {
            break;
        }
        
        if (ch == '\n') {
            break;
        }
        
        line += ch;
    }
    
    return line;
}

bool SocketWrapper::setNonBlocking(bool nonBlocking) {
    if (!m_isValid) return false;
    
#ifdef _WIN32
    u_long mode = nonBlocking ? 1 : 0;
    return ioctlsocket(m_socket, FIONBIO, &mode) == 0;
#else
    int flags = fcntl(m_socket, F_GETFL, 0);
    if (flags < 0) return false;
    
    flags = nonBlocking ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
    return fcntl(m_socket, F_SETFL, flags) == 0;
#endif
}

bool SocketWrapper::setReuseAddr(bool reuse) {
    if (!m_isValid) return false;
    
    int optval = reuse ? 1 : 0;
    return setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, 
                     (const char*)&optval, sizeof(optval)) == 0;
}

void SocketWrapper::close() {
    if (m_isValid && m_socket != INVALID_SOCKET_FD) {
#ifdef _WIN32
        closesocket(m_socket);
#else
        ::close(m_socket);
#endif
        m_socket = INVALID_SOCKET_FD;
        m_isValid = false;
    }
}

std::string SocketWrapper::getLastError() {
#ifdef _WIN32
    int errorCode = WSAGetLastError();
    char buffer[256];
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL, errorCode, 0, buffer, sizeof(buffer), NULL);
    return std::string(buffer);
#else
    return std::string(strerror(errno));
#endif
}
