/*
 * auth.c
 */

#include "auth.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_log.h>
#include <string.h>
#include "wiegand_reader.h"

#include "nvs_flash.h"
#include "nvs.h"

#define MAX_TAGS 50

static const char *TAG = "Auth";
static bool enabled = true;
static char valid_tags[MAX_TAGS][AUTH_TAG_MAX_LEN];
static int tag_count = 0;

// Fila de eventos enviada ao EVSE Manager
static QueueHandle_t event_queue = NULL;

// ===========================
// Persistência em NVS
// ===========================

static void load_auth_config(void) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open("auth", NVS_READONLY, &handle);
    if (err == ESP_OK) {
        uint8_t val;
        if (nvs_get_u8(handle, "enabled", &val) == ESP_OK) {
            enabled = val;
            ESP_LOGI(TAG, "Loaded auth enabled = %d", enabled);
        }
        nvs_close(handle);
    } else {
        ESP_LOGW(TAG, "No stored auth config found. Using default.");
    }
}

static void save_auth_config(void) {
    nvs_handle_t handle;
    if (nvs_open("auth", NVS_READWRITE, &handle) == ESP_OK) {
        nvs_set_u8(handle, "enabled", enabled);
        nvs_commit(handle);
        nvs_close(handle);
        ESP_LOGI(TAG, "Auth config saved: enabled = %d", enabled);
    } else {
        ESP_LOGE(TAG, "Failed to save auth config.");
    }
}

// ===========================
// Internos
// ===========================

static bool is_tag_valid(const char *tag) {
    for (int i = 0; i < tag_count; i++) {
        if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0) {
            return true;
        }
    }
    return false;
}

// ===========================
// API pública
// ===========================

void auth_set_event_queue(QueueHandle_t queue) {
    event_queue = queue;
}

void auth_set_enabled(bool value) {
    enabled = value;
    save_auth_config();
    ESP_LOGI(TAG, "Auth %s", enabled ? "ENABLED" : "DISABLED");
}

bool auth_is_enabled(void) {
    return enabled;
}

bool auth_add_tag(const char *tag) {
    if (tag_count >= MAX_TAGS) return false;
    if (!tag || strlen(tag) >= AUTH_TAG_MAX_LEN) return false;
    if (is_tag_valid(tag)) return true;

    strncpy(valid_tags[tag_count], tag, AUTH_TAG_MAX_LEN - 1);
    valid_tags[tag_count][AUTH_TAG_MAX_LEN - 1] = '\0';
    tag_count++;
    ESP_LOGI(TAG, "Tag added: %s", tag);
    return true;
}

bool auth_remove_tag(const char *tag) {
    for (int i = 0; i < tag_count; i++) {
        if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0) {
            for (int j = i; j < tag_count - 1; j++) {
                strncpy(valid_tags[j], valid_tags[j + 1], AUTH_TAG_MAX_LEN);
            }
            tag_count--;
            ESP_LOGI(TAG, "Tag removed: %s", tag);
            return true;
        }
    }
    return false;
}

bool auth_tag_exists(const char *tag) {
    return is_tag_valid(tag);
}

void auth_list_tags(void) {
    ESP_LOGI(TAG, "Registered Tags (%d):", tag_count);
    for (int i = 0; i < tag_count; i++) {
        ESP_LOGI(TAG, "- %s", valid_tags[i]);
    }
}

void auth_init(void) {
    load_auth_config();      // carrega estado de ativação
    initWiegand();           // inicia leitor RFID
}

// Processa uma tag lida (chamada pelo leitor)
void auth_process_tag(const char *tag) {
    if (!tag || !auth_is_enabled()) {
        ESP_LOGW(TAG, "Auth disabled or NULL tag received.");
        return;
    }

    auth_event_t event;
    strncpy(event.tag, tag, AUTH_TAG_MAX_LEN - 1);
    event.tag[AUTH_TAG_MAX_LEN - 1] = '\0';
    event.authorized = is_tag_valid(tag);

    ESP_LOGI(TAG, "Tag %s: %s", tag, event.authorized ? "AUTHORIZED" : "DENIED");

    if (event_queue) {
        if (xQueueSend(event_queue, &event, pdMS_TO_TICKS(100)) != pdPASS) {
            ESP_LOGW(TAG, "Auth event queue full, dropping tag: %s", tag);
        }
    } else {
        ESP_LOGW(TAG, "Auth event queue not set");
    }
}
