/**
 * @file potentiometer_manager.c
 * @brief Potentiometer Manager Implementation - ESP-IDF v4.4 Compatible
 * 
 * Features:
 * - Dual ADC reading (Volume + Brightness)
 * - Moving average filter (smoothing)
 * - Automatic monitoring task
 * - Callback on changes
 * - Direct ST7789 brightness control
 * 
 * NOTE: Simplified for ESP-IDF v4.4 - removed esp_adc_cal (not available in v4.4)
 */

#include <string.h>
#include "esp_log.h"
#include "driver/adc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "potentiometer_manager.h"
#include "st7789.h"
#include "hardware_config.h"

static const char *TAG = "POTI";

// ADC Configuration
#define ADC_SAMPLES         8       // Samples for averaging
#define POTI_THRESHOLD      5       // Change threshold (%)
#define POTI_UPDATE_MS      100     // Update interval

// Current values
static uint8_t current_volume = 50;
static uint8_t current_brightness = 80;

// Monitoring task
static TaskHandle_t poti_task_handle = NULL;
static bool poti_task_running = false;
static poti_change_callback_t change_callback = NULL;

/**
 * @brief Initialize ADC for potentiometers
 */
static esp_err_t poti_adc_init(void)
{
    // Configure ADC1 (Volume - GPIO 3)
    adc1_config_width(POTI_ADC_WIDTH);
    adc1_config_channel_atten(ADC1_CHANNEL_2, POTI_ADC_ATTEN);  // GPIO 3 = ADC1_CH2
    
    // Configure ADC2 (Brightness - GPIO 46)  
    adc2_config_channel_atten(ADC2_CHANNEL_5, POTI_ADC_ATTEN);  // GPIO 46 = ADC2_CH5
    
    ESP_LOGI(TAG, "ADC configured for potentiometers");
    
    return ESP_OK;
}

/**
 * @brief Read ADC with averaging (simplified - no calibration)
 */
static uint32_t poti_read_adc1_averaged(void)
{
    uint32_t sum = 0;
    
    for (int i = 0; i < ADC_SAMPLES; i++) {
        int raw = adc1_get_raw(ADC1_CHANNEL_2);
        if (raw >= 0) {
            sum += raw;
        }
        vTaskDelay(pdMS_TO_TICKS(1));
    }
    
    return sum / ADC_SAMPLES;
}

static uint32_t poti_read_adc2_averaged(void)
{
    uint32_t sum = 0;
    int valid_samples = 0;
    
    for (int i = 0; i < ADC_SAMPLES; i++) {
        int raw;
        
        // ADC2 read (can fail if WiFi is active!)
        esp_err_t ret = adc2_get_raw(ADC2_CHANNEL_5, POTI_ADC_WIDTH, &raw);
        if (ret == ESP_OK && raw >= 0) {
            sum += raw;
            valid_samples++;
        } else {
            ESP_LOGD(TAG, "ADC2 read failed (WiFi active?)");
        }
        
        vTaskDelay(pdMS_TO_TICKS(1));
    }
    
    if (valid_samples == 0) {
        return 0;  // No valid readings
    }
    
    return sum / valid_samples;
}

/**
 * @brief Convert raw ADC value to percentage (0-100%)
 * For 12-bit ADC: 0-4095 range
 */
static uint8_t raw_to_percent(uint32_t raw_value, uint32_t max_value)
{
    if (raw_value >= max_value) return 100;
    return (raw_value * 100) / max_value;
}

/**
 * @brief Potentiometer monitoring task
 */
static void poti_monitor_task(void *arg)
{
    ESP_LOGI(TAG, "Potentiometer monitoring task started");
    
    while (poti_task_running) {
        // Read potentiometers (raw ADC values)
        uint32_t volume_raw = poti_read_adc1_averaged();
        uint32_t brightness_raw = poti_read_adc2_averaged();
        
        // Convert to percentage (12-bit ADC: 0-4095)
        uint8_t new_volume = raw_to_percent(volume_raw, 4095);
        uint8_t new_brightness = raw_to_percent(brightness_raw, 4095);
        
        // Clamp brightness to minimum (display shouldn't be completely off)
        if (new_brightness < LCD_BCKL_MIN) {
            new_brightness = LCD_BCKL_MIN;
        }
        
        // Check if changed significantly
        bool volume_changed = abs(new_volume - current_volume) >= POTI_THRESHOLD;
        bool brightness_changed = abs(new_brightness - current_brightness) >= POTI_THRESHOLD;
        
        if (volume_changed || brightness_changed) {
            current_volume = new_volume;
            current_brightness = new_brightness;
            
            ESP_LOGD(TAG, "Volume: %d%%, Brightness: %d%%", 
                     current_volume, current_brightness);
            
            // Update display brightness immediately
            st7789_set_backlight(current_brightness);
            
            // Call callback if registered
            if (change_callback != NULL) {
                change_callback(current_volume, current_brightness);
            }
        }
        
        vTaskDelay(pdMS_TO_TICKS(POTI_UPDATE_MS));
    }
    
    ESP_LOGI(TAG, "Potentiometer monitoring task stopped");
    vTaskDelete(NULL);
}

// ===========================================
// Public API
// ===========================================

esp_err_t poti_manager_init(void)
{
    ESP_LOGI(TAG, "Initializing Potentiometer Manager...");
    
    // Initialize ADC
    esp_err_t ret = poti_adc_init();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize ADC");
        return ret;
    }
    
    // Read initial values
    poti_update();
    
    ESP_LOGI(TAG, "Potentiometer Manager initialized");
    ESP_LOGI(TAG, "  Volume: %d%%, Brightness: %d%%", 
             current_volume, current_brightness);
    
    return ESP_OK;
}

esp_err_t poti_manager_start(poti_change_callback_t callback)
{
    if (poti_task_running) {
        ESP_LOGW(TAG, "Potentiometer task already running");
        return ESP_OK;
    }
    
    change_callback = callback;
    poti_task_running = true;
    
    BaseType_t ret = xTaskCreate(
        poti_monitor_task,
        "poti_monitor",
        4096,
        NULL,
        5,  // Priority
        &poti_task_handle
    );
    
    if (ret != pdPASS) {
        ESP_LOGE(TAG, "Failed to create potentiometer task!");
        poti_task_running = false;
        return ESP_FAIL;
    }
    
    ESP_LOGI(TAG, "Potentiometer monitoring started");
    
    return ESP_OK;
}

void poti_manager_stop(void)
{
    if (!poti_task_running) {
        return;
    }
    
    ESP_LOGI(TAG, "Stopping potentiometer monitoring...");
    poti_task_running = false;
    
    // Task will delete itself
}

uint8_t poti_get_volume(void)
{
    return current_volume;
}

uint8_t poti_get_brightness(void)
{
    return current_brightness;
}

esp_err_t poti_update(void)
{
    // Manual single update (without task)
    uint32_t volume_raw = poti_read_adc1_averaged();
    uint32_t brightness_raw = poti_read_adc2_averaged();
    
    current_volume = raw_to_percent(volume_raw, 4095);
    current_brightness = raw_to_percent(brightness_raw, 4095);
    
    if (current_brightness < LCD_BCKL_MIN) {
        current_brightness = LCD_BCKL_MIN;
    }
    
    // Update display brightness
    st7789_set_backlight(current_brightness);
    
    ESP_LOGD(TAG, "Manual update: Volume %d%%, Brightness %d%%", 
             current_volume, current_brightness);
    
    return ESP_OK;
}
