#include "meter_manager.h"
#include "esp_log.h"
#include "meter_ade7758.h"
#include "meter_orno513.h"
#include "meter_orno516.h"
#include "meter_zigbee.h"
#include "nvs_flash.h"
#include "nvs.h"
#include <string.h>
#include "network_events.h"


static const char *TAG = "meter_manager";

// Tipos de medidores EVSE e GRID
static meter_type_t meter_evse_type = METER_TYPE_NONE;
static meter_type_t meter_grid_type = METER_TYPE_NONE;

#define NVS_NAMESPACE "meterconfig"
#define NVS_EVSE_MODEL "evse_model"
#define NVS_GRID_MODEL "grid_model"


static void meter_manager_network_event_handler(void* arg, esp_event_base_t base, int32_t event_id, void* data){

    if (base != NETWORK_EVENTS) return;

    switch (event_id) {
        case NETWORK_EVENT_AP_STARTED:
            ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STARTED, parando medidor de grid");
            meter_manager_grid_stop();
            break;

        case NETWORK_EVENT_AP_STOP:
            ESP_LOGI(TAG, "Recebido NETWORK_EVENT_AP_STOP, reiniciando medidor de grid");
            meter_manager_grid_start();
            break;

        case NETWORK_EVENT_STA_GOT_IP:
            ESP_LOGI(TAG, "Recebido NETWORK_EVENT_STA_GOT_IP");
            // opcional: reiniciar ou logar
            break;

        default:
            break;
    }
}


// Função unificada para ler ou inicializar um modelo de medidor
static esp_err_t load_or_init_meter_model(const char *key, meter_type_t *type) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open NVS handle for %s: %s", key, esp_err_to_name(err));
        return err;
    }

    uint8_t value = 0;
    err = nvs_get_u8(handle, key, &value);
    if (err == ESP_OK && value <= METER_TYPE_TRIF_ZIGBEE) {
        *type = (meter_type_t)value;
        ESP_LOGI(TAG, "Loaded meter type %d from NVS key '%s'", value, key);
    } else {
        *type = METER_TYPE_NONE;
        nvs_set_u8(handle, key, *type);
        nvs_commit(handle);
        ESP_LOGW(TAG, "Invalid or missing key '%s', setting default (NONE)", key);
    }

    nvs_close(handle);
    return ESP_OK;
}

static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_type) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open NVS handle for writing");
        return err;
    }

    err = nvs_set_u8(handle, key, (uint8_t)meter_type);
    if (err == ESP_OK) {
        err = nvs_commit(handle);
        ESP_LOGI(TAG, "Saved meter type %d to NVS key '%s'", meter_type, key);
    } else {
        ESP_LOGE(TAG, "Failed to write meter type to NVS key '%s'", key);
    }

    nvs_close(handle);
    return err;
}


/**
 * @brief Initializes the meter manager system.
 *
 * This function initializes both the EVSE and GRID meters,
 * and registers the event handler to listen for NETWORK_EVENTS
 * (e.g., AP started/stopped, STA got IP).
 *
 * @return esp_err_t ESP_OK on success, or an error code.
 */
esp_err_t meter_manager_init(void) {
    esp_err_t err;

    // Initialize EVSE meter
    //err = meter_manager_evse_init();
    //if (err != ESP_OK) return err;

    // Initialize GRID meter
    err = meter_manager_grid_init();
    if (err != ESP_OK) return err;

    // Register handler for custom network events
    ESP_LOGI(TAG, "Registering network event handler");
    return esp_event_handler_register(NETWORK_EVENTS,
                                      ESP_EVENT_ANY_ID,
                                      meter_manager_network_event_handler,
                                      NULL);
}


/**
 * @brief Starts all configured meters (EVSE and GRID).
 *
 * This function starts the EVSE and GRID meters based on their configured types.
 * It does not register event handlers — that is handled by `meter_manager_init()`.
 *
 * @return esp_err_t ESP_OK on success, or an error code from one of the start calls.
 */
esp_err_t meter_manager_start(void) {
    esp_err_t err;

    // Start EVSE meter
    //err = meter_manager_evse_start();
    //if (err != ESP_OK) return err;

    // Start GRID meter
    err = meter_manager_grid_start();
    if (err != ESP_OK) return err;

    return ESP_OK;
}


/**
 * @brief Stops all meters and unregisters event handlers.
 *
 * This function gracefully stops the EVSE and GRID meters
 * and unregisters the previously registered network event handler.
 *
 * @return esp_err_t ESP_OK on success, or an error code.
 */
esp_err_t meter_manager_stop(void) {
    esp_err_t err;

    // Stop EVSE meter
    //err = meter_manager_evse_stop();
    //if (err != ESP_OK) return err;

    // Stop GRID meter
    err = meter_manager_grid_stop();
    if (err != ESP_OK) return err;

    return ESP_OK;
}




// Função para inicializar o medidor EVSE
esp_err_t meter_manager_evse_init() {
    esp_err_t err = load_or_init_meter_model(NVS_EVSE_MODEL, &meter_evse_type);
    if (err != ESP_OK) return err;

    ESP_LOGI(TAG, "Initializing EVSE meter of type %s", meter_type_to_str(meter_evse_type));

    switch (meter_evse_type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: return meter_ade7758_init();
        case METER_TYPE_ORNO513: return meter_orno513_init();
        case METER_TYPE_ORNO516: return meter_orno516_init();
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init();
        default: return ESP_ERR_INVALID_ARG;
    }
}

esp_err_t meter_manager_grid_init() {
    esp_err_t err = load_or_init_meter_model(NVS_GRID_MODEL, &meter_grid_type);
    if (err != ESP_OK) return err;

    ESP_LOGI(TAG, "Initializing GRID meter of type %s", meter_type_to_str(meter_grid_type));

    switch (meter_grid_type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: return meter_ade7758_init();
        case METER_TYPE_ORNO513: return meter_orno513_init();
        case METER_TYPE_ORNO516: return meter_orno516_init();
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init();
        default: return ESP_ERR_INVALID_ARG;
    }
}

esp_err_t meter_manager_grid_start() {
    meter_type_t type = meter_manager_grid_get_model();
    switch (type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: return meter_ade7758_start();
        case METER_TYPE_ORNO513: return meter_orno513_start();
        case METER_TYPE_ORNO516: return meter_orno516_start();
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start();
        default: return ESP_ERR_INVALID_ARG;
    }
}

esp_err_t meter_manager_grid_stop(void) {
    meter_type_t type = meter_manager_grid_get_model();
    switch (type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: meter_ade7758_stop(); break;
        case METER_TYPE_ORNO513: meter_orno513_stop(); break;
        case METER_TYPE_ORNO516: meter_orno516_stop(); break;
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break;
        default: return ESP_ERR_INVALID_ARG;
    }
    return ESP_OK;
}


esp_err_t meter_manager_evse_set_model(meter_type_t meter_type) {
    meter_evse_type = meter_type;
    return write_meter_model_to_nvs(NVS_EVSE_MODEL, meter_evse_type);
}

esp_err_t meter_manager_grid_set_model(meter_type_t meter_type) {
    meter_grid_type = meter_type;
    return write_meter_model_to_nvs(NVS_GRID_MODEL, meter_grid_type);
}

esp_err_t meter_manager_evse_start() {
    meter_type_t type = meter_manager_evse_get_model();
    switch (type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: return meter_ade7758_start();
        case METER_TYPE_ORNO513: return meter_orno513_start();
        case METER_TYPE_ORNO516: return meter_orno516_start();
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start();
        default: return ESP_ERR_INVALID_ARG;
    }
}

esp_err_t meter_manager_evse_stop(void) {
    meter_type_t type = meter_manager_evse_get_model();
    switch (type) {
        case METER_TYPE_NONE: return ESP_OK;
        case METER_TYPE_ADE7758: meter_ade7758_stop(); break;
        case METER_TYPE_ORNO513: meter_orno513_stop(); break;
        case METER_TYPE_ORNO516: meter_orno516_stop(); break;
        case METER_TYPE_MONO_ZIGBEE:
        case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break;
        default: return ESP_ERR_INVALID_ARG;
    }
    return ESP_OK;
}

bool meter_manager_evse_is_enabled(void) {
    return meter_manager_evse_get_model() != METER_TYPE_NONE;
}

meter_type_t meter_manager_evse_get_model(void) {
    return meter_evse_type;
}

meter_type_t meter_manager_grid_get_model(void) {
    return meter_grid_type;
}

const char* meter_type_to_str(meter_type_t type) {
    switch (type) {
        case METER_TYPE_NONE: return "NENHUM";
        case METER_TYPE_ADE7758: return "IC ADE";
        case METER_TYPE_ORNO513: return "ORNO-513";
        case METER_TYPE_ORNO516: return "ORNO-516";
        case METER_TYPE_MONO_ZIGBEE: return "MONO-ZIGBEE";
        case METER_TYPE_TRIF_ZIGBEE: return "TRIF-ZIGBEE";
        default: return "NENHUM";
    }
}

meter_type_t string_to_meter_type(const char *str) {
    if (!str) return METER_TYPE_NONE;
    if (strcmp(str, "IC ADE") == 0) return METER_TYPE_ADE7758;
    if (strcmp(str, "ORNO-513") == 0) return METER_TYPE_ORNO513;
    if (strcmp(str, "ORNO-516") == 0) return METER_TYPE_ORNO516;
    if (strcmp(str, "MONO-ZIGBEE") == 0) return METER_TYPE_MONO_ZIGBEE;
    if (strcmp(str, "TRIF-ZIGBEE") == 0) return METER_TYPE_TRIF_ZIGBEE;
    return METER_TYPE_NONE;
}
