// Cliente TCP de conteo: envía la entrada estándar y muestra la respuesta.
//   wc_client <host> <puerto>  <  archivo
#define _POSIX_C_SOURCE 200809L

#include "io_util.h"

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

// Prueba cada dirección que devuelve getaddrinfo hasta que una se conecte.
static int connect_to(const char *host, const char *port) {
    struct addrinfo hints;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;      // IPv4 o IPv6
    hints.ai_socktype = SOCK_STREAM;  // TCP

    struct addrinfo *results;
    int err = getaddrinfo(host, port, &hints, &results);
    if (err != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
        return -1;
    }

    int fd = -1;
    for (struct addrinfo *ai = results; ai != NULL; ai = ai->ai_next) {
        fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (fd == -1) {
            perror("socket");
            continue;
        }
        if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) {
            break;
        }
        perror("connect");
        close_checked(fd);
        fd = -1;
    }
    freeaddrinfo(results);
    return fd;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "uso: %s <host> <puerto>\n", argv[0]);
        return EXIT_FAILURE;
    }
    int fd = connect_to(argv[1], argv[2]);
    if (fd == -1) {
        return EXIT_FAILURE;
    }

    char buf[4096];
    size_t n;
    while ((n = fread(buf, 1, sizeof buf, stdin)) > 0) {
        if (send_all(fd, buf, n) == -1) {
            close_checked(fd);
            return EXIT_FAILURE;
        }
    }
    if (ferror(stdin)) {
        fprintf(stderr, "error al leer la entrada estándar\n");
        close_checked(fd);
        return EXIT_FAILURE;
    }

    // Avisamos que ya no enviaremos más; el socket sigue abierto para recibir.
    if (shutdown(fd, SHUT_WR) == -1) {
        perror("shutdown");
        close_checked(fd);
        return EXIT_FAILURE;
    }

    for (;;) {
        ssize_t r = recv(fd, buf, sizeof buf, 0);
        if (r == -1) {
            perror("recv");
            close_checked(fd);
            return EXIT_FAILURE;
        }
        if (r == 0) {
            break;
        }
        if (fwrite(buf, 1, (size_t)r, stdout) != (size_t)r) {
            fprintf(stderr, "error al escribir la salida\n");
            close_checked(fd);
            return EXIT_FAILURE;
        }
    }
    close_checked(fd);
    return EXIT_SUCCESS;
}
