/*
 * Creator: Naman Dixit
 * Notice: © Copyright 2020 Naman Dixit
 */

/*
 * Creator: Naman Dixit
 * Notice: © Copyright 2019 Naman Dixit
 */

#include "nlib/nlib.h"

#undef internal_malloc
#undef internal_free

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <ctype.h>
#include <assert.h>
#include <signal.h>
#include <librdkafka/rdkafka.h>


# if defined(COMPILER_CLANG)
#  pragma clang diagnostic push
#   pragma clang diagnostic ignored "-Wpadded"
#   pragma clang diagnostic ignored "-Wfloat-equal"
# endif
#include "cJSON/cJSON.h"
#include "cJSON/cJSON.c"
# if defined(COMPILER_CLANG)
#  pragma clang diagnostic pop
# endif

#include "kafka.h"

int main(int argc, char** argv)
{
    if (argc < 2) {
        printf("Error: Pass the amount of memory\n");
        exit(-1);
    }

    Sint memory_required = (Sint)strtol(argv[1], NULL, 10);

    Kafka kafka = {0};

    kafka.writer = kafkaCreateWriter(&kafka, "10.129.6.5:9092");

#define CREATE_TOPIC(s)                                 \
    do {                                                \
        if (kafkaCreateTopic(&kafka, s, 1, 1) == -1) {  \
            rd_kafka_destroy(kafka.writer);             \
            return -1;                                  \
        }                                               \
    } while (0)

    CREATE_TOPIC("REQUEST_DM_2_RM"); //
    CREATE_TOPIC("RESPONSE_RM_2_DM");
    CREATE_TOPIC("REQUEST_RM_2_RD");
    CREATE_TOPIC("RESPONSE_RD_2_RM"); //
    CREATE_TOPIC("JOIN_RD_2_RM"); //
    CREATE_TOPIC("HEARTBEAT_RD_2_RM"); //
    CREATE_TOPIC("LOG_COMMON"); //

    kafka.reader = kafkaCreateReader(&kafka, "10.129.6.5:9092");

    rd_kafka_topic_partition_list_t *kafka_reader_topics = rd_kafka_topic_partition_list_new(1);

    kafkaSubscribe(&kafka, kafka_reader_topics, "RESPONSE_RM_2_DM");

    rd_kafka_resp_err_t kafka_reader_topics_err = rd_kafka_subscribe(kafka.reader, kafka_reader_topics);
    rd_kafka_topic_partition_list_destroy(kafka_reader_topics);

    if (kafka_reader_topics_err) {
        fprintf(stderr, "Subscribe failed: %s\n",
                rd_kafka_err2str(kafka_reader_topics_err));
        rd_kafka_destroy(kafka.reader);
        return -1;
    }

    Char *output = NULL;

    Sint id = (Sint)time(NULL);
    sbufPrint(output, "{\n\"resource_id\": \"%d\"", id);
    sbufPrint(output, ",\n\"timestamp\": %d", id);
    sbufPrint(output, ",\n\"memory\": %d", memory_required);
    sbufPrint(output, "\n}\n");

    printf("Sending to Arbiter:\n%s\n", cJSON_Print(cJSON_Parse(output)));

    printf("%ld\n", time(0));
    if (output != NULL) {
        if (!kafkaWrite(kafka.writer, "REQUEST_DM_2_RM", "rm_test", output)) {
            return -1;
        }
    }
    printf("%ld\n", time(0));

    rd_kafka_message_t *kafka_message_read = rd_kafka_consumer_poll(kafka.reader, 10);
    while (true) {
        if (kafka_message_read != NULL) {
            const Char *json_error = NULL;
            cJSON *root = cJSON_ParseWithOpts((char *)kafka_message_read->payload, &json_error, true);
            Sint id_now = 0;
            if (cJSON_GetObjectItem(root, "resource_id") == NULL) {
                goto skip_message;
            }
            id_now = atoi(cJSON_GetObjectItem(root, "resource_id")->valuestring);
            if (id_now == id) {
                break;
            } else {
            skip_message:
                printf("Found a cranky old message: %d\n", id_now);
                rd_kafka_message_destroy(kafka_message_read);
            }
        }
        kafka_message_read = rd_kafka_consumer_poll(kafka.reader, 10);
    }

    if (kafka_message_read != NULL) {
        if (kafka_message_read->err) {
            /* Consumer error: typically just informational. */
            fprintf(stderr, "Consumer error: %s\n",
                    rd_kafka_message_errstr(kafka_message_read));
        } else {
            fprintf(stderr,
                    "Received message on %s [%d] "
                    "at offset %"PRId64": \n%s\n",
                    rd_kafka_topic_name(kafka_message_read->rkt),
                    (int)kafka_message_read->partition, kafka_message_read->offset,
                    cJSON_Print(cJSON_Parse((char *)kafka_message_read->payload)));

            char *buffer = (char *)kafka_message_read->payload;

            const Char *json_error = NULL;
            cJSON *root = cJSON_ParseWithOpts(buffer, &json_error, true);

            if (root == NULL) {
                // TODO(naman): Error
            } else {
                cJSON *array = cJSON_GetObjectItem(root, "resource_id");
                cJSON *elem = NULL;
                cJSON_ArrayForEach(elem, array) {
                    printf("%s\n", elem->valuestring);
                }
            }
        }
        rd_kafka_message_destroy(kafka_message_read);
    }

    for (Size i = 0; i < sbufElemin(kafka.topics); i++) {
        rd_kafka_topic_destroy(kafka.topics[i]);
    }
    rd_kafka_consumer_close(kafka.reader);
    rd_kafka_destroy(kafka.reader);
    for (Size i = 0; i < sbufElemin(kafka.queues); i++) {
        rd_kafka_queue_destroy(kafka.queues[i]);
    }
    rd_kafka_destroy(kafka.writer);

    return 0;
}
