// Cliente UDP de hora.
//   time_client [-c] [-w espera_ms] <host> <puerto>
//     -c   llama a connect antes de enviar
#define _POSIX_C_SOURCE 200809L

#include "io_util.h"

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

int main(int argc, char *argv[]) {
    bool use_connect = false;
    long wait_ms = 1000;
    int opt;
    while ((opt = getopt(argc, argv, "cw:")) != -1) {
        if (opt == 'c') {
            use_connect = true;
        } else if (opt == 'w') {
            wait_ms = strtol(optarg, NULL, 10);
        } else {
            return EXIT_FAILURE;
        }
    }
    if (argc - optind != 2 || wait_ms <= 0) {
        fprintf(stderr, "uso: %s [-c] [-w espera_ms] <host> <puerto>\n", argv[0]);
        return EXIT_FAILURE;
    }

    struct addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    struct addrinfo *server;
    int err = getaddrinfo(argv[optind], argv[optind + 1], &hints, &server);
    if (err != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
        return EXIT_FAILURE;
    }

    int fd = socket(server->ai_family, server->ai_socktype, server->ai_protocol);
    if (fd == -1) {
        perror("socket");
        return EXIT_FAILURE;
    }
    // UDP no avisa si algo se pierde: sin un plazo, recv podría esperar para siempre.
    struct timeval limit = {.tv_sec = wait_ms / 1000, .tv_usec = (wait_ms % 1000) * 1000};
    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &limit, sizeof limit) == -1) {
        perror("setsockopt");
        return EXIT_FAILURE;
    }

    const char request[] = "hora?";
    ssize_t sent;
    if (use_connect) {
        // connect en UDP no envía nada: fija el destino y filtra lo que llega.
        if (connect(fd, server->ai_addr, server->ai_addrlen) == -1) {
            perror("connect");
            return EXIT_FAILURE;
        }
        sent = send(fd, request, sizeof request - 1, 0);
    } else {
        sent = sendto(fd, request, sizeof request - 1, 0,
                      server->ai_addr, server->ai_addrlen);
    }
    if (sent == -1) {
        perror("send");
        return EXIT_FAILURE;
    }
    printf("enviados %zd bytes\n", sent);
    fflush(stdout);

    char reply[128];
    ssize_t n = recv(fd, reply, sizeof reply - 1, 0);
    if (n == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            printf("sin respuesta después de %ld ms\n", wait_ms);
            freeaddrinfo(server);
            close_checked(fd);
            return 2;
        }
        perror("recv");
        return EXIT_FAILURE;
    }
    reply[n] = '\0';
    printf("hora: %s", reply);
    freeaddrinfo(server);
    close_checked(fd);
    return EXIT_SUCCESS;
}
