#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/rmt_rx.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "ir_validator.h"
#include "ir_path.h"
#include "ir_rc6_decoder.h"

#define RMT_RX_GPIO_NUM         GPIO_NUM_1
#define RMT_RESOLUTION_HZ       1000000  // 1MHz resolution, 1 tick = 1μs
#define RMT_MEM_BLOCK_SYMBOLS   128       // Memory block size

static const char* TAG = "RMT_NEW";

static int signals_count = 0;

// RMT receive handle
static rmt_channel_handle_t rx_channel = NULL;
static QueueHandle_t receive_queue;

// Callback function for RMT receive
static bool IRAM_ATTR rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_wakeup = pdFALSE;
    QueueHandle_t receive_queue = (QueueHandle_t)user_data;
    
    // Send the received data to the queue
    xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
    
    return high_task_wakeup == pdTRUE;
}

void rmt_new_init() {
    ESP_LOGI(TAG, "Configuring new RMT RX driver...");
    
    // Create receive queue
    receive_queue = xQueueCreate(4, sizeof(rmt_rx_done_event_data_t));
    assert(receive_queue);

    sd_card_init();
    
    // RX channel configuration
    rmt_rx_channel_config_t rx_config = {
        .gpio_num = RMT_RX_GPIO_NUM,
        .clk_src = RMT_CLK_SRC_DEFAULT,
        .resolution_hz = RMT_RESOLUTION_HZ,
        .mem_block_symbols = RMT_MEM_BLOCK_SYMBOLS,
        .flags.invert_in = false,
        .flags.with_dma = false,
    };
    
    ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_config, &rx_channel));
    
    // Register RX callback
    rmt_rx_event_callbacks_t cbs = {
        .on_recv_done = rmt_rx_done_callback,
    };
    ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(rx_channel, &cbs, receive_queue));
    
    // Configure receive parameters
    rmt_receive_config_t receive_config = {
        .signal_range_min_ns = 1000,     // Minimum pulse width: 1μs
        .signal_range_max_ns = 30000000, // Maximum pulse width: 12ms
    };
    
    // Enable the channel
    ESP_ERROR_CHECK(rmt_enable(rx_channel));
    
    // Start receiving
    rmt_symbol_word_t *raw_symbols = malloc(RMT_MEM_BLOCK_SYMBOLS * sizeof(rmt_symbol_word_t));
    assert(raw_symbols);
    
    ESP_ERROR_CHECK(rmt_receive(rx_channel, raw_symbols, RMT_MEM_BLOCK_SYMBOLS * sizeof(rmt_symbol_word_t), &receive_config));
    
    ESP_LOGI(TAG, "RMT RX successfully configured:");
    ESP_LOGI(TAG, "- GPIO: %d", RMT_RX_GPIO_NUM);
    ESP_LOGI(TAG, "- Resolution: %lu Hz (1 tick = 1μs)", (unsigned long)RMT_RESOLUTION_HZ);
    ESP_LOGI(TAG, "- Symbols per block: %d", RMT_MEM_BLOCK_SYMBOLS);
    ESP_LOGI(TAG, "- Waiting for IR signals...");
}

void process_rmt_symbols(rmt_symbol_word_t* symbols, size_t symbol_num) {
    ESP_LOGI(TAG, "=== RECEIVED %d RMT SYMBOLS ===", symbol_num);

    signals_count++;
    
    uint32_t total_duration = 0;

    // VALIDATE PROTOCOL
    if (symbol_num == 0 || symbols == NULL) {
        ESP_LOGI(TAG, "No symbols received");
        return;
    }

    // Create temporary array of rmt_symbol_t
    rmt_symbol_t* converted_symbols = malloc(sizeof(rmt_symbol_t) * symbol_num);
    if (converted_symbols == NULL) {
        ESP_LOGE(TAG, "Failed to allocate memory for converted symbols");
        return;
    }

    // Convert from rmt_symbol_word_t format to rmt_symbol_t
    for (size_t i = 0; i < symbol_num; i++) {
        converted_symbols[i].L0 = symbols[i].level0;
        converted_symbols[i].D0 = symbols[i].duration0;
        converted_symbols[i].L1 = symbols[i].level1;
        converted_symbols[i].D1 = symbols[i].duration1;
    }

    // Validate protocol
    Protocol protocol = validate_signal(converted_symbols, symbol_num);

    free(converted_symbols);
    // VALIDATE PROTOCOL

    char filename[64];

    // SAVE
    switch (protocol)
    {
        case NEC_PROTOCOL:
            snprintf(filename, sizeof(filename), "nec-%d.ir", signals_count);
            ESP_LOGE(TAG, "SAVING NEC PROTOCOL");
            break;
        
        case RC6_PROTOCOL:
            rc6_decoded_data_t rc6_data;
            decode_rc6(symbols, symbol_num, &rc6_data);
            snprintf(filename, sizeof(filename), "nec-%d.ir", signals_count);
            ESP_LOGI(TAG, "RC6 DECODED: 0x%04X | Mode: %u | Toggle: %u | Command: 0x%02X", 
                    rc6_data.raw_value, rc6_data.mode, rc6_data.toggle, rc6_data.command);
            break;
        default:
            snprintf(filename, sizeof(filename), "unknown-%d.ir", signals_count);
            break;
    }

    esp_err_t err = save_ir_symbols(filename, symbols, symbol_num);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Error saving file: %s", esp_err_to_name(err));
    }

    // SAVE


    // PRINT SIGNALS
    for (size_t i = 0; i < symbol_num; i++) {
        uint32_t duration0 = symbols[i].duration0;
        uint32_t duration1 = symbols[i].duration1;
        uint32_t level0 = symbols[i].level0;
        uint32_t level1 = symbols[i].level1;
        
        total_duration += duration0 + duration1;
        
        printf("Symbol %2d: L0=%lu D0=%5lu | L1=%lu D1=%5lu", 
               (int)i, (unsigned long)level0, (unsigned long)duration0, 
               (unsigned long)level1, (unsigned long)duration1);
        
        // Detect long pulses (possible idle periods)
        if (duration0 > 5000 || duration1 > 5000) {
            printf(" ← LONG PULSE");
        }
        
        // Check for end of transmission markers
        if (i == symbol_num - 1) {
            if (duration1 == 0) {
                printf(" ← END OF TRANSMISSION");
            }
        }
        
        printf("\n");
    }
    // PRINT SIGNALS

    printf("Total duration: %lu μs (%.2f ms)\n", (unsigned long)total_duration, total_duration/1000.0);
    ESP_LOGI(TAG, "Processing completed!");
    printf("==========================================\n");
}

void rmt_rx_task(void *arg) {
    rmt_rx_done_event_data_t rx_data;
    rmt_symbol_word_t *raw_symbols = malloc(RMT_MEM_BLOCK_SYMBOLS * sizeof(rmt_symbol_word_t));
    assert(raw_symbols);
    
    while (1) {
        // Wait for RX done event
        if (xQueueReceive(receive_queue, &rx_data, portMAX_DELAY) == pdPASS) {
            // Process received data
            process_rmt_symbols((rmt_symbol_word_t*)rx_data.received_symbols, rx_data.num_symbols);
            
            // Start next receive
            rmt_receive_config_t receive_config = {
                .signal_range_min_ns = 1000,     // 1μs minimum
                .signal_range_max_ns = 12000000, // 12ms maximum
            };
            
            // Clear buffer and restart reception
            memset(raw_symbols, 0, RMT_MEM_BLOCK_SYMBOLS * sizeof(rmt_symbol_word_t));
            ESP_ERROR_CHECK(rmt_receive(rx_channel, raw_symbols, RMT_MEM_BLOCK_SYMBOLS * sizeof(rmt_symbol_word_t), &receive_config));
        }
        
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

void app_main() {
    ESP_LOGI(TAG, "Starting RMT RX with new API...");
    
    // Initialize RMT
    rmt_new_init();
    
    // Create task to handle RX events
    xTaskCreate(rmt_rx_task, "rmt_rx_task", 4096, NULL, 5, NULL);
    
    ESP_LOGI(TAG, "RMT system initialized. Ready to receive!");
    
    // Main loop - just keep alive
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}