#include "net.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>


Packet* create_packet(PacketType type, const void* data, uint16_t size) {
    Packet* pkt = malloc(sizeof(Packet) + size);
    pkt->type = type;
    pkt->size = size;
    memcpy(pkt->data, data, size);
    return pkt;
}

int serialize_packet(Packet* pkt, char* buffer) {
    buffer[0] = pkt->type;
    buffer[1] = (pkt->size >> 8) & 0xFF;
    buffer[2] = pkt->size & 0xFF;
    memcpy(buffer + 3, pkt->data, pkt->size);
    return 3 + pkt->size;
}

Packet* deserialize_packet(const char* buffer, int len) {
    if (len < 3) return NULL;
    uint8_t type = buffer[0];
    uint16_t size = ((uint8_t)buffer[1] << 8) | (uint8_t)buffer[2];
    if (size > len - 3) return NULL;
    return create_packet(type, buffer + 3, size);
}

void destroy_packet(Packet* pkt) {
    free(pkt);
}

void net_init() {
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
}

void net_cleanup() {
    WSACleanup();
}

SOCKET net_connect(const char* ip, int port) {
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port)
    };
    inet_pton(AF_INET, ip, &addr.sin_addr);
    connect(sock, (struct sockaddr*)&addr, sizeof(addr));
    return sock;
}

SOCKET net_bind_and_listen(int port) {
    SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
        .sin_addr.s_addr = INADDR_ANY
    };
    bind(server, (struct sockaddr*)&addr, sizeof(addr));
    listen(server, SOMAXCONN);
    return server;
}

SOCKET net_accept(SOCKET server) {
    return accept(server, NULL, NULL);
}


void set_socket_nonblocking(SOCKET sock, int enable)
{
    u_long mode = (enable) ? 1 : 0;
    ioctlsocket(sock, FIONBIO, &mode);
}
