#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Variables globales compartidas
long par = 0;
long impar = 0;

// Mutexes para proteger el acceso a las variables compartidas
pthread_mutex_t mutex_par = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_impar = PTHREAD_MUTEX_INITIALIZER;

// Función que ejecutarán los hilos
void *thread_routine(void *arg) {
  int orden = *((int *)arg);
  free(arg);

  long *suma_local = malloc(sizeof(long));
  *suma_local = 0;

  // Generar 5 números aleatorios
  for (int i = 0; i < 5; i++) {
    int num = rand() % 11;
    *suma_local += num;
    if (orden % 2 == 0) {
      pthread_mutex_lock(&mutex_par);
      par += num;
      pthread_mutex_unlock(&mutex_par);
    } else {
      pthread_mutex_lock(&mutex_impar);
      impar += num;
      pthread_mutex_unlock(&mutex_impar);
    }
  }

  pthread_exit((void *)suma_local);
}

int main(int argc, char *argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Uso: %s <N>\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  int N = atoi(argv[1]);
  if (N <= 0) {
    fprintf(stderr, "El número de hilos N debe ser mayor que 0\n");
    exit(EXIT_FAILURE);
  }

  srand(time(NULL));
  pthread_t *threads = malloc(N * sizeof(pthread_t));

  // CREATES
  for (int i = 0; i < N; i++) {
    int *arg = malloc(sizeof(int));
    *arg = i + 1;

    if (pthread_create(&threads[i], NULL, thread_routine, (void *)arg)) {
      perror("Error al crear hilo");
      exit(EXIT_FAILURE);
    }
  }

  // Esperar a que terminen los hilos y recoger sus resultados
  for (int i = 0; i < N; i++) {
    long *ret;
    if (pthread_join(threads[i], (void **)&ret) != 0) {
      perror("Error al hacer join");
      exit(EXIT_FAILURE);
    }

    if (ret != NULL) {
      printf("Main()... La hebra de orden de creacion %d devolvio el valor de suma: %ld\n", i + 1, *ret);
      free(ret); // Liberar la memoria devuelta por el hilo
    }
  }

  printf("\nMain()... Valor de la variable compartida impar:  %ld\n", impar);
  printf("Main()... Valor de la variable compartida par:    %ld\n", par);

  // Limpieza
  free(threads);
  pthread_mutex_destroy(&mutex_par);
  pthread_mutex_destroy(&mutex_impar);

  return 0;
}