#include <inttypes.h>  // for PRIu32
#include "evse_state.h"
#include "evse_api.h"
#include "evse_limits.h"
#include "evse_meter.h"
#include "evse_session.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"


// ========================
// External state references
// ========================

//extern evse_state_t current_state;       // Current EVSE FSM state
//extern TickType_t session_start_tick;    // Timestamp of charging session start

// ========================
// Concurrency protection
// ========================

static portMUX_TYPE evse_mux = portMUX_INITIALIZER_UNLOCKED;

// ========================
// Runtime state (volatile)
// ========================

static bool     limit_reached               = false;
static uint32_t consumption_limit           = 0;     // Energy limit in Wh
static uint32_t charging_time_limit         = 0;     // Time limit in seconds
static uint16_t under_power_limit           = 0;     // Minimum acceptable power in W

// ========================
// Default (persistent) limits
// ========================

static uint32_t default_consumption_limit   = 0;
static uint32_t default_charging_time_limit = 0;
static uint16_t default_under_power_limit   = 0;

// ========================
// Limit status flag
// ========================

bool evse_get_limit_reached(void) {
    bool val;
    portENTER_CRITICAL(&evse_mux);
    val = limit_reached;
    portEXIT_CRITICAL(&evse_mux);
    return val;
}

void evse_set_limit_reached(bool v) {
    portENTER_CRITICAL(&evse_mux);
    limit_reached = v;
    portEXIT_CRITICAL(&evse_mux);
}

// ========================
// Runtime limit accessors
// ========================

uint32_t evse_get_consumption_limit(void) {
    uint32_t val;
    portENTER_CRITICAL(&evse_mux);
    val = consumption_limit;
    portEXIT_CRITICAL(&evse_mux);
    return val;
}

void evse_set_consumption_limit(uint32_t value) {
    portENTER_CRITICAL(&evse_mux);
    consumption_limit = value;
    portEXIT_CRITICAL(&evse_mux);
}

uint32_t evse_get_charging_time_limit(void) {
    uint32_t val;
    portENTER_CRITICAL(&evse_mux);
    val = charging_time_limit;
    portEXIT_CRITICAL(&evse_mux);
    return val;
}

void evse_set_charging_time_limit(uint32_t value) {
    portENTER_CRITICAL(&evse_mux);
    charging_time_limit = value;
    portEXIT_CRITICAL(&evse_mux);
}

uint16_t evse_get_under_power_limit(void) {
    uint16_t val;
    portENTER_CRITICAL(&evse_mux);
    val = under_power_limit;
    portEXIT_CRITICAL(&evse_mux);
    return val;
}

void evse_set_under_power_limit(uint16_t value) {
    portENTER_CRITICAL(&evse_mux);
    under_power_limit = value;
    portEXIT_CRITICAL(&evse_mux);
}

// ========================
// Default (persistent) limit accessors
// These values can be stored/restored via NVS
// ========================

uint32_t evse_get_default_consumption_limit(void) {
    return default_consumption_limit;
}

void evse_set_default_consumption_limit(uint32_t value) {
    default_consumption_limit = value;
}

uint32_t evse_get_default_charging_time_limit(void) {
    return default_charging_time_limit;
}

void evse_set_default_charging_time_limit(uint32_t value) {
    default_charging_time_limit = value;
}

uint16_t evse_get_default_under_power_limit(void) {
    return default_under_power_limit;
}

void evse_set_default_under_power_limit(uint16_t value) {
    default_under_power_limit = value;
}

bool evse_is_limit_reached(void) {
    return evse_get_limit_reached();
}

// ========================
// Limit checking logic
// This function must be called periodically while charging.
// It will flag the session as "limit reached" when thresholds are violated.
// ========================
void evse_limits_check(void) {
    // Only check during an active charging session
    if (!evse_state_is_charging(evse_get_state())) {
        return;
    }

    evse_session_t sess;
    // Retrieve accumulated data for the current session
    if (!evse_session_get(&sess) || !sess.is_current) {
        // If there's no active session, abort
        return;
    }

    bool reached = false;

    // 1) Energy consumption limit (Wh)
    if (consumption_limit > 0 && sess.energy_wh >= consumption_limit) {
        ESP_LOGW("EVSE_LIMITS",
                 "Energy limit reached: %" PRIu32 " Wh ≥ %" PRIu32 " Wh",
                 sess.energy_wh, consumption_limit);
        reached = true;
    }

    // 2) Charging time limit (seconds)
    if (charging_time_limit > 0 && sess.duration_s >= charging_time_limit) {
        ESP_LOGW("EVSE_LIMITS",
                 "Charging time limit reached: %" PRIu32 " s ≥ %" PRIu32 " s",
                 sess.duration_s, charging_time_limit);
        reached = true;
    }

    // 3) Under-power limit (instantaneous power)
    uint32_t inst_power = evse_meter_get_instant_power();
    if (under_power_limit > 0 && inst_power < under_power_limit) {
        ESP_LOGW("EVSE_LIMITS",
                "Under-power limit reached: %" PRIu32 " W < %" PRIu32 " W",
                (uint32_t)inst_power,
                (uint32_t)under_power_limit);
        reached = true;
    }

    if (reached) {
        evse_set_limit_reached(true);
    }
}