#include "led_manager.h"
#include <esp_log.h>
#include <driver/gpio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>

static const char *TAG = "LED_MANAGER";

// LED state tracking
static struct {
    led_state_t status_led;
    led_state_t ethernet_led;
    led_state_t wifi_led;
    led_state_t scan_led;
    bool ethernet_active;
    bool wifi_active;
    bool scan_active;
    uint32_t blink_counter;
} s_led_state = {0};

static TimerHandle_t s_led_timer = NULL;

// Forward declarations
static void led_timer_callback(TimerHandle_t timer);
static void update_led_pattern(int gpio_num, led_state_t state, uint32_t counter);

esp_err_t led_manager_init(void)
{
    // Configure GPIO pins
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = (1ULL << LED_STATUS_GPIO) | 
                       (1ULL << LED_ETHERNET_GPIO) | 
                       (1ULL << LED_WIFI_GPIO) | 
                       (1ULL << LED_SCAN_GPIO),
        .pull_down_en = 0,
        .pull_up_en = 0,
    };
    
    esp_err_t ret = gpio_config(&io_conf);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to configure GPIO: %s", esp_err_to_name(ret));
        return ret;
    }
    
    // Initialize LED states
    s_led_state.status_led = LED_STATE_OFF;
    s_led_state.ethernet_led = LED_STATE_OFF;
    s_led_state.wifi_led = LED_STATE_OFF;
    s_led_state.scan_led = LED_STATE_OFF;
    s_led_state.ethernet_active = false;
    s_led_state.wifi_active = false;
    s_led_state.scan_active = false;
    s_led_state.blink_counter = 0;
    
    // Turn off all LEDs initially
    gpio_set_level(LED_STATUS_GPIO, 0);
    gpio_set_level(LED_ETHERNET_GPIO, 0);
    gpio_set_level(LED_WIFI_GPIO, 0);
    gpio_set_level(LED_SCAN_GPIO, 0);
    
    // Create timer for LED updates
    s_led_timer = xTimerCreate("led_timer", pdMS_TO_TICKS(100), pdTRUE, NULL, led_timer_callback);
    if (s_led_timer) {
        xTimerStart(s_led_timer, 0);
    }
    
    ESP_LOGI(TAG, "LED manager initialized");
    return ESP_OK;
}

esp_err_t led_manager_set_state(int gpio_num, led_state_t state)
{
    switch (gpio_num) {
        case LED_STATUS_GPIO:
            s_led_state.status_led = state;
            break;
        case LED_ETHERNET_GPIO:
            s_led_state.ethernet_led = state;
            break;
        case LED_WIFI_GPIO:
            s_led_state.wifi_led = state;
            break;
        case LED_SCAN_GPIO:
            s_led_state.scan_led = state;
            break;
        default:
            return ESP_ERR_INVALID_ARG;
    }
    
    return ESP_OK;
}

esp_err_t led_manager_set_status(led_status_t status)
{
    switch (status) {
        case LED_STATUS_SYSTEM_READY:
            led_manager_set_state(LED_STATUS_GPIO, LED_STATE_BLINK_SLOW);
            break;
        case LED_STATUS_SYSTEM_ERROR:
            led_manager_set_state(LED_STATUS_GPIO, LED_STATE_BLINK_FAST);
            break;
        case LED_STATUS_ETHERNET_CONNECTED:
            led_manager_set_state(LED_ETHERNET_GPIO, LED_STATE_ON);
            s_led_state.ethernet_active = true;
            break;
        case LED_STATUS_ETHERNET_DISCONNECTED:
            led_manager_set_state(LED_ETHERNET_GPIO, LED_STATE_OFF);
            s_led_state.ethernet_active = false;
            break;
        case LED_STATUS_WIFI_AP_ACTIVE:
            led_manager_set_state(LED_WIFI_GPIO, LED_STATE_BLINK_SLOW);
            s_led_state.wifi_active = true;
            break;
        case LED_STATUS_WIFI_CLIENT_CONNECTED:
            led_manager_set_state(LED_WIFI_GPIO, LED_STATE_ON);
            break;
        case LED_STATUS_SCAN_ACTIVE:
            led_manager_set_state(LED_SCAN_GPIO, LED_STATE_BLINK_FAST);
            s_led_state.scan_active = true;
            break;
        case LED_STATUS_SCAN_COMPLETE:
            led_manager_set_state(LED_SCAN_GPIO, LED_STATE_PULSE);
            s_led_state.scan_active = false;
            break;
        case LED_STATUS_SD_CARD_ACCESS:
            led_manager_set_state(LED_STATUS_GPIO, LED_STATE_PULSE);
            break;
        case LED_STATUS_OTA_UPDATE:
            led_manager_set_state(LED_STATUS_GPIO, LED_STATE_BLINK_FAST);
            break;
        default:
            return ESP_ERR_INVALID_ARG;
    }
    
    return ESP_OK;
}

void led_manager_update(void)
{
    // Update LED patterns based on current state
    update_led_pattern(LED_STATUS_GPIO, s_led_state.status_led, s_led_state.blink_counter);
    update_led_pattern(LED_ETHERNET_GPIO, s_led_state.ethernet_led, s_led_state.blink_counter);
    update_led_pattern(LED_WIFI_GPIO, s_led_state.wifi_led, s_led_state.blink_counter);
    update_led_pattern(LED_SCAN_GPIO, s_led_state.scan_led, s_led_state.blink_counter);
}

void led_manager_set_ethernet_activity(bool active)
{
    s_led_state.ethernet_active = active;
    if (active) {
        led_manager_set_state(LED_ETHERNET_GPIO, LED_STATE_ON);
    } else {
        led_manager_set_state(LED_ETHERNET_GPIO, LED_STATE_OFF);
    }
}

void led_manager_set_wifi_activity(bool active)
{
    s_led_state.wifi_active = active;
    if (active) {
        led_manager_set_state(LED_WIFI_GPIO, LED_STATE_BLINK_SLOW);
    } else {
        led_manager_set_state(LED_WIFI_GPIO, LED_STATE_OFF);
    }
}

void led_manager_set_scan_activity(bool active)
{
    s_led_state.scan_active = active;
    if (active) {
        led_manager_set_state(LED_SCAN_GPIO, LED_STATE_BLINK_FAST);
    } else {
        led_manager_set_state(LED_SCAN_GPIO, LED_STATE_OFF);
    }
}

// Internal helper functions

static void led_timer_callback(TimerHandle_t timer)
{
    s_led_state.blink_counter++;
    led_manager_update();
}

static void update_led_pattern(int gpio_num, led_state_t state, uint32_t counter)
{
    int level = 0;
    
    switch (state) {
        case LED_STATE_OFF:
            level = 0;
            break;
        case LED_STATE_ON:
            level = 1;
            break;
        case LED_STATE_BLINK_SLOW:
            level = (counter % 10) < 5 ? 1 : 0; // 0.5Hz blink
            break;
        case LED_STATE_BLINK_FAST:
            level = (counter % 4) < 2 ? 1 : 0; // 2Hz blink
            break;
        case LED_STATE_PULSE:
            level = (counter % 20) < 2 ? 1 : 0; // Brief pulse every 2 seconds
            break;
        default:
            level = 0;
            break;
    }
    
    gpio_set_level(gpio_num, level);
} 