#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define HASH_TABLE_SIZE 128

typedef struct token_entry {
    char *username;
    char *token;
    time_t expiry_time;
    struct token_entry *next;
} token_entry_t;

static token_entry_t *token_table[HASH_TABLE_SIZE] = {0};

/* Hash function */
static unsigned int hash_username(const char *username) {
    unsigned int hash = 5381;
    int c;
    while ((c = *username++))
        hash = ((hash << 5) + hash) + c;
    return hash % HASH_TABLE_SIZE;
}

static void free_entry(token_entry_t *entry) {
    if (!entry) return;
    free(entry->username);
    free(entry->token);
    free(entry);
}

/* API: Set token */
void ns_gmf_set_token(char *username, char *token, int expiry_sec) {
    unsigned int index = hash_username(username);
    token_entry_t *curr = token_table[index];
    time_t now = time(NULL);

    while (curr) {
        if (strcmp(curr->username, username) == 0) {
            free(curr->token);
            curr->token = strdup(token);
            curr->expiry_time = now + expiry_sec;
            return;
        }
        curr = curr->next;
    }

    token_entry_t *new_entry = malloc(sizeof(token_entry_t));
    if (!new_entry) return;

    new_entry->username = strdup(username);
    new_entry->token = strdup(token);
    new_entry->expiry_time = now + expiry_sec;
    new_entry->next = token_table[index];
    token_table[index] = new_entry;
}

/* API: Get token */
char *ns_gmf_get_token(char *username) {
    unsigned int index = hash_username(username);
    token_entry_t *curr = token_table[index];
    token_entry_t *prev = NULL;
    time_t now = time(NULL);

    while (curr) {
        if (strcmp(curr->username, username) == 0) {
            if (curr->expiry_time <= now) {
                if (prev)
                    prev->next = curr->next;
                else
                    token_table[index] = curr->next;

                free_entry(curr);
                return NULL;
            }
            return curr->token;
        }
        prev = curr;
        curr = curr->next;
    }
    return NULL;
}

/* ---------------- MAIN FOR TESTING ---------------- */

int main(void) {
    char *token;

    printf("Setting token for user1 (expiry 3 seconds)...\n");
    ns_gmf_set_token("user1", "token_abc", 3);

    printf("Setting token for user2 (expiry 5 seconds)...\n");
    ns_gmf_set_token("user2", "token_xyz", 5);

    printf("\nFetching tokens immediately:\n");
    token = ns_gmf_get_token("user1");
    printf("user1 token: %s\n", token ? token : "NULL");

    token = ns_gmf_get_token("user2");
    printf("user2 token: %s\n", token ? token : "NULL");

    printf("\nSleeping for 4 seconds...\n");
    sleep(4);

    printf("\nFetching tokens after sleep:\n");
    token = ns_gmf_get_token("user1");
    printf("user1 token (expected expired): %s\n", token ? token : "NULL");

    token = ns_gmf_get_token("user2");
    printf("user2 token (expected valid): %s\n", token ? token : "NULL");

    printf("\nOverwriting token for user2...\n");
    ns_gmf_set_token("user2", "token_new", 5);

    token = ns_gmf_get_token("user2");
    printf("user2 token after overwrite: %s\n", token ? token : "NULL");

    printf("\nFetching non-existent user:\n");
    token = ns_gmf_get_token("user3");
    printf("user3 token: %s\n", token ? token : "NULL");

    return 0;
}

