#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

// const char MESSAGE[] = "Guess who's back!\n";

int main(int argc, char *argv[])
{

    time_t ticks = time(NULL);
    char MESSAGE[28] = {'\0'};
    snprintf(MESSAGE, sizeof(MESSAGE), "%.24s\r\n", ctime(&ticks));

    int simpleSocket = 0;
    int simplePort = 0;
    int returnStatus = 0;
    struct sockaddr_in simpleServer;

    if (argc < 1 || argc > 2)
    {
        fprintf(stderr, "Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (simpleSocket == -1)
    {

        fprintf(stderr, "Could not create a socket!\n");
        exit(1);
    }
    else
    {
        fprintf(stderr, "Socket created!\n");
    }

    /* retrieve the port number for listening */
    if (argc == 2)
    {
        simplePort = atoi(argv[1]);
        if (simplePort < 10000 || simplePort > 12000)
        {
            fprintf(stderr, "Port must be in range [10000, 12000]\n");
            exit(1);
        }
    }
    else
    {
        srand(time(NULL));
        simplePort = (rand() % 1999) + 10000;
    }

    /* setup the address structure */
    /* use INADDR_ANY to bind to all local addresses  */
    memset(&simpleServer, '\0', sizeof(simpleServer));
    simpleServer.sin_family = AF_INET;
    simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
    simpleServer.sin_port = htons(simplePort);

    /*  bind to the address and port with our socket */
    returnStatus = bind(simpleSocket, (struct sockaddr *)&simpleServer,
                        sizeof(simpleServer));

    if (returnStatus == 0)
    {
        fprintf(stderr, "Bind completed on port %d!\n", simplePort);
    }
    else
    {
        fprintf(stderr, "Could not bind to address!\n");
        close(simpleSocket);
        exit(1);
    }

    /* lets listen on the socket for connections      */
    returnStatus = listen(simpleSocket, 5);

    if (returnStatus == -1)
    {
        fprintf(stderr, "Cannot listen on socket!\n");
        close(simpleSocket);
        exit(1);
    }

    while (1)
    {
        struct sockaddr_in clientName = {0};
        int simpleChildSocket = 0;
        int clientNameLength = sizeof(clientName);

        /* wait here */

        simpleChildSocket =
            accept(simpleSocket, (struct sockaddr *)&clientName, &clientNameLength);

        if (simpleChildSocket == -1)
        {
            fprintf(stderr, "Cannot accept connections!\n");
            close(simpleSocket);
            exit(1);
        }

        /* handle the new connection request  */
        /* write out our message to the client */

        // Read message from client
        char bufferRead[256] = {'\0'};
        printf("%zu\n\n", read(simpleChildSocket, bufferRead, sizeof(bufferRead)));
        printf("Received: %s\n", bufferRead);
        char valueToSend[256] = {'\0'};
        snprintf(valueToSend, sizeof(valueToSend), "%s", bufferRead);
        write(simpleChildSocket, valueToSend, sizeof(valueToSend));

        close(simpleChildSocket);
    }

    close(simpleSocket);
    return 0;
}