#include "led_strip.h"
#include "esp_log.h"
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char *TAG = "led_strip";

struct led_strip_t {
    uint32_t length;
    uint8_t *buffer;
    rmt_channel_handle_t channel;
    uint32_t resolution;
};

typedef struct {
    uint8_t g;
    uint8_t r;
    uint8_t b;
} __attribute__((packed)) grb_pixel_t;

esp_err_t led_strip_new_rmt_device(const led_strip_config_t *config, led_strip_handle_t *ret_strip) {
    if (!config || !ret_strip) return ESP_ERR_INVALID_ARG;

    led_strip_handle_t strip = calloc(1, sizeof(struct led_strip_t));
    if (!strip) return ESP_ERR_NO_MEM;

    strip->length = config->strip_length;
    strip->resolution = config->resolution_hz;
    strip->channel = config->rmt_channel;
    strip->buffer = calloc(strip->length, sizeof(grb_pixel_t));
    if (!strip->buffer) {
        free(strip);
        return ESP_ERR_NO_MEM;
    }

    *ret_strip = strip;
    ESP_LOGI(TAG, "Novo LED strip criado (%lu LEDs)", (unsigned long)strip->length);
    return ESP_OK;
}

esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint8_t red, uint8_t green, uint8_t blue) {
    if (!strip || index >= strip->length) return ESP_ERR_INVALID_ARG;
    grb_pixel_t *pixels = (grb_pixel_t *)strip->buffer;
    pixels[index].g = green;
    pixels[index].r = red;
    pixels[index].b = blue;
    return ESP_OK;
}

esp_err_t led_strip_refresh(led_strip_handle_t strip) {
    if (!strip) return ESP_ERR_INVALID_ARG;
    // Envia os dados via RMT
    rmt_transmit_config_t tx_conf = { .loop_count = 0 };
    ESP_ERROR_CHECK(rmt_transmit(strip->channel, NULL, strip->buffer, strip->length * sizeof(grb_pixel_t), &tx_conf));
    ESP_ERROR_CHECK(rmt_tx_wait_all_done(strip->channel, portMAX_DELAY));
    return ESP_OK;
}

esp_err_t led_strip_clear(led_strip_handle_t strip) {
    if (!strip) return ESP_ERR_INVALID_ARG;
    memset(strip->buffer, 0, strip->length * sizeof(grb_pixel_t));
    return led_strip_refresh(strip);
}
