#include <sys/cdefs.h>
#include <stdio.h>
#include <inttypes.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <mqtt_client.h>
#include <esp_crt_bundle.h>
#include <led_strip.h>
#include <esp_timer.h>
#include <driver/gpio.h>

#include "LED_Segments.h"

// Constants
#define LED_STRIP_RMT_RES_HZ  (10 * 1000 * 1000)
#define TOPIC_BUFFER_SIZE 50

// Global variables
LED_Segments segments[CONFIG_LED_SEGMENT_COUNT];

esp_mqtt_client_handle_t mqtt_client;
led_strip_handle_t led_internal;
led_strip_handle_t led_segments;

uint64_t last_time_blink = 0;
uint64_t last_time_pulse = 0;
uint64_t last_time_walk_fill = 0;
int refresh_pulse = CONFIG_PATTERN_TIME / 2 / 255;
int refresh_blink = CONFIG_PATTERN_TIME / CONFIG_BLINK_COUNT;
int refresh_walk_fill = CONFIG_PATTERN_TIME / CONFIG_SEGMENT_COUNT;
int value_blink = 0;
int value_pulse = 0;
int value_walk_fill = 0;
int direction_pulse = 0;




// Function prototypes
esp_err_t init_mqtt(void);

esp_err_t handle_mqtt_cmd(char *topic, uint8_t *payload, int length);

// helper functions
uint8_t limit(uint8_t value) {
    return (LIMIT * value) / 255;
}


// Event handlers

static void network_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, LIMIT, LIMIT, 0));
        ESP_ERROR_CHECK(led_strip_refresh(debug_led));
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, LIMIT, LIMIT, 0));
        ESP_ERROR_CHECK(led_strip_refresh(debug_led));
        esp_wifi_connect();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
        ESP_LOGI("network", "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        ESP_ERROR_CHECK(init_mqtt());
        ESP_LOGI("main", "init_mqtt done");
        ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0, LIMIT, 0));
        ESP_ERROR_CHECK(led_strip_refresh(debug_led));
        vTaskDelay(pdMS_TO_TICKS(1000));
        ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, 0, 0, 0));
        ESP_ERROR_CHECK(led_strip_refresh(debug_led));
    }
}

/*
 * @brief Event handler registered to receive MQTT events
 *
 *  This function is called by the MQTT client event loop.
 *
 * @param handler_args user data registered to the event.
 * @param base Event base for the handler(always MQTT Base in this example).
 * @param event_id The id for the received event.
 * @param event_data The data for the event, esp_mqtt_event_handle_t.
 */
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
    ESP_LOGD("mqtt", "Event dispatched from event loop base=%s, event_id=%" PRIu32, base, event_id);
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;
    switch ((esp_mqtt_event_id_t) event_id) {
        case MQTT_EVENT_CONNECTED:
            ESP_LOGI("mqtt", "MQTT_EVENT_CONNECTED");

            char id[6] = "00000";
            sprintf(id, "%05d", CONFIG_FABLIGHT_ID);

            // Register Reader
            msg_id = esp_mqtt_client_publish(client, "fablight", id, 0, 0, 0);
            ESP_LOGI("mqtt", "sent publish successful, msg_id=%d", msg_id);

            char topic_recv[TOPIC_BUFFER_SIZE];
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/+/static", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/+/pulse", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/+/blink", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/+/walk", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/+/fill", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/buzzer", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/sync", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/sync");
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);
            snprintf(topic_recv, TOPIC_BUFFER_SIZE, "fablight/%05d/clear", CONFIG_FABLIGHT_ID);
            msg_id = esp_mqtt_client_subscribe(client, topic_recv, 0);
            ESP_LOGI("mqtt", "sent subscribe successful, msg_id=%d", msg_id);

            break;
        case MQTT_EVENT_DISCONNECTED:
            ESP_LOGI("mqtt", "MQTT_EVENT_DISCONNECTED");
            break;

        case MQTT_EVENT_SUBSCRIBED:
            ESP_LOGI("mqtt", "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_UNSUBSCRIBED:
            ESP_LOGI("mqtt", "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_PUBLISHED:
            ESP_LOGI("mqtt", "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
            break;
        case MQTT_EVENT_DATA:
            ESP_LOGI("mqtt", "MQTT_EVENT_DATA");
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
            printf("DATA=%.*s\r\n", event->data_len, event->data);

            char* topic = strndup(event->topic, event->topic_len);

            esp_err_t ret = handle_mqtt_cmd(topic, (uint8_t *) event->data, event->data_len);

            free(topic);

            if (ret != ESP_OK) {
                ESP_LOGE("mqtt", "Error handling MQTT command: %s", esp_err_to_name(ret));
            }
            break;
        case MQTT_EVENT_ERROR:
            ESP_LOGE("mqtt", "MQTT_EVENT_ERROR");
            if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
                ESP_LOGE("mqtt", "Last error code reported from esp-tls: 0x%x",
                         event->error_handle->esp_tls_last_esp_err);
                ESP_LOGE("mqtt", "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err);
                ESP_LOGE("mqtt", "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno,
                         strerror(event->error_handle->esp_transport_sock_errno));
            } else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
                ESP_LOGE("mqtt", "Connection refused error: 0x%x", event->error_handle->connect_return_code);
            } else {
                ESP_LOGW("mqtt", "Unknown error type: 0x%x", event->error_handle->error_type);
            }
            break;
        default:
            ESP_LOGI("mqtt", "Other event id:%d", event->event_id);
            break;
    }
}

// Initialization Functions

esp_err_t init_led_strip() {
    // LED strip general initialization, according to your led board design
    led_strip_config_t debug_led_config = {
            .strip_gpio_num = CONFIG_PIN_DEBUG_LED,   // The GPIO that connected to the LED strip's data line
            .max_leds = 1,        // The number of LEDs in the strip,
            .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
            .led_model = LED_MODEL_WS2812,            // LED strip model
            .flags.invert_out = false,                // whether to invert the output signal
    };

    // LED strip backend configuration: RMT
    led_strip_rmt_config_t debug_led_rmt_config = {
            .clk_src = RMT_CLK_SRC_DEFAULT,        // different clock source can lead to different power consumption
            .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency
            .flags.with_dma = false,               // DMA feature is available on ESP target like ESP32-S3
    };
    ESP_ERROR_CHECK(led_strip_new_rmt_device(&debug_led_config, &debug_led_rmt_config, &debug_led));
    ESP_LOGI("led", "Created LED strip object with RMT backend for debug LED");

    // LED strip general initialization, according to your led board design
    led_strip_config_t strip_config = {
            .strip_gpio_num = CONFIG_PIN_SEGMENT_DATA,   // The GPIO that connected to the LED strip's data line
            .max_leds = CONFIG_SEGMENT_COUNT * CONFIG_SEGMENT_SIZE,        // The number of LEDs in the strip,
            .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
            .led_model = LED_MODEL_WS2812,            // LED strip model
            .flags.invert_out = false,                // whether to invert the output signal
    };

    // LED strip backend configuration: RMT
    led_strip_rmt_config_t rmt_config = {
            .clk_src = RMT_CLK_SRC_DEFAULT,        // different clock source can lead to different power consumption
            .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency
            .flags.with_dma = true,               // DMA feature is available on ESP target like ESP32-S3
    };
    ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
    ESP_LOGI("led", "Created LED strip object with RMT backend for Segment LEDs");

    return ESP_OK;
}

esp_err_t init_gpio(void) {
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = (1ULL << CONFIG_PIN_BUZZER);
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    esp_err_t ret = gpio_config(&io_conf);
    ESP_ERROR_CHECK(ret);
    return ret;
}

esp_err_t init_eventloop() {
    esp_err_t ret = esp_event_loop_create_default();
    ESP_ERROR_CHECK(ret);
    return ret;
}

esp_err_t init_wifi() {
    esp_err_t ret;
    ret = esp_netif_init();
    ESP_ERROR_CHECK(ret);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ret = esp_wifi_init(&cfg);
    ESP_ERROR_CHECK(ret);

    ret = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &network_event_handler, NULL, NULL);
    ESP_ERROR_CHECK(ret);
    ret = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &network_event_handler, NULL, NULL);
    ESP_ERROR_CHECK(ret);


    // Initialize default station as network interface instance (esp-netif)
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    // Initialize and start WiFi
    wifi_config_t wifi_config = {
            .sta = {
                    .ssid = CONFIG_WIFI_SSID,
                    .password = CONFIG_WIFI_PASSWORD,
                    .scan_method = CONFIG_WIFI_FAST_SCAN ? WIFI_FAST_SCAN : WIFI_ALL_CHANNEL_SCAN,
                    .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
                    .threshold.rssi = -127,
                    .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            },
    };
    ret = esp_wifi_set_mode(WIFI_MODE_STA);
    ESP_ERROR_CHECK(ret);
    ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    ESP_ERROR_CHECK(ret);
    ret = esp_wifi_start();
    ESP_ERROR_CHECK(ret);

    return ret;
}

esp_err_t init_nvs() {
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    return ret;
}

esp_err_t init_mqtt() {
    esp_err_t ret;
    const esp_mqtt_client_config_t mqtt_cfg = {
            .broker = {
                    .address.uri = CONFIG_BROKER_URI,
                    .verification.crt_bundle_attach = esp_crt_bundle_attach
            }
    };

    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
    /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
    ret = esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, NULL);
    ESP_ERROR_CHECK(ret);
    ret = esp_mqtt_client_start(client);
    ESP_ERROR_CHECK(ret);

    mqtt_client = client;

    return ret;
}

// Buisness Logic

esp_err_t handle_mqtt_cmd(char *topic, uint8_t *payload, int length) {
    int topic_len = (int) strlen(topic);
    int mode_static_len = (int) strlen("/static");
    int mode_pulse_len = (int) strlen("/pulse");
    int mode_blink_len = (int) strlen("/blink");
    int mode_fill_len = (int) strlen("/fill");
    int mode_walk_len = (int) strlen("/walk");
    int buzzer_len = (int) strlen("/buzzer");
    int sync_len = (int) strlen("/sync");
    int clear_len = (int) strlen("/clear");

    if (!strcmp(topic + topic_len - mode_static_len, "/static")) {
        if (length != 3) {
            return ESP_FAIL;
        }

        char str_id[6] = {0};
        strncpy(str_id, topic + topic_len - mode_static_len - 5, 5);
        int id = strtol(str_id, NULL, 10);

        if (id >= CONFIG_SEGMENT_COUNT) {
            return ESP_FAIL;
        }
        for (int i = 0; i < CONFIG_SEGMENT_SIZE; i++) {
            ESP_ERROR_CHECK(
                    led_strip_set_pixel(led_strip, id * CONFIG_SEGMENT_SIZE + i, limit(payload[0]), limit(payload[1]),
                                        limit(payload[2])));
        }
        ESP_ERROR_CHECK(led_strip_refresh(led_strip));

        led_color[id][0] = MODE_STATIC;
        led_color[id][1] = limit(payload[0]);
        led_color[id][2] = limit(payload[1]);
        led_color[id][3] = limit(payload[2]);

        ESP_LOGI("mqtt_handler", "set segment %d to static color %d %d %d", id, led_color[id][1], led_color[id][2], led_color[id][3]);
    }

    if (!strcmp(topic + topic_len - mode_pulse_len, "/pulse")) {
        if (length != 3) {
            return ESP_FAIL;
        }

        char str_id[6] = {0};
        strncpy(str_id, topic + topic_len - mode_pulse_len - 5, 5);
        int id = strtol(str_id, NULL, 10);

        if (id >= CONFIG_SEGMENT_COUNT) {
            return ESP_FAIL;
        }

        led_color[id][0] = MODE_PULSE;
        led_color[id][1] = limit(payload[0]);
        led_color[id][2] = limit(payload[1]);
        led_color[id][3] = limit(payload[2]);

        ESP_LOGI("mqtt_handler", "set segment %d to pulse color %d %d %d", id, led_color[id][1], led_color[id][2], led_color[id][3]);
    }

    if (!strcmp(topic + topic_len - mode_blink_len, "/blink")) {
        if (length != 3) {
            return ESP_FAIL;
        }

        char str_id[6] = {0};
        strncpy(str_id, topic + topic_len - mode_blink_len - 5, 5);
        int id = strtol(str_id, NULL, 10);

        if (id >= CONFIG_SEGMENT_COUNT) {
            return ESP_FAIL;
        }

        led_color[id][0] = MODE_BLINK;
        led_color[id][1] = limit(payload[0]);
        led_color[id][2] = limit(payload[1]);
        led_color[id][3] = limit(payload[2]);

        ESP_LOGI("mqtt_handler", "set segment %d to blink color %d %d %d", id, led_color[id][1], led_color[id][2], led_color[id][3]);
    }

    if (!strcmp(topic + topic_len - mode_fill_len, "/fill")) {
        if (length != 3) {
            return ESP_FAIL;
        }

        char str_id[6] = {0};
        strncpy(str_id, topic + topic_len - mode_fill_len - 5, 5);
        int id = strtol(str_id, NULL, 10);

        if (id >= CONFIG_SEGMENT_COUNT) {
            return ESP_FAIL;
        }

        led_color[id][0] = MODE_FILL;
        led_color[id][1] = limit(payload[0]);
        led_color[id][2] = limit(payload[1]);
        led_color[id][3] = limit(payload[2]);

        ESP_LOGI("mqtt_handler", "set segment %d to fill color %d %d %d", id, led_color[id][1], led_color[id][2], led_color[id][3]);
    }

    if (!strcmp(topic + topic_len - mode_walk_len, "/walk")) {
        if (length != 3) {
            return ESP_FAIL;
        }

        char str_id[6] = {0};
        strncpy(str_id, topic + topic_len - mode_walk_len - 5, 5);
        int id = strtol(str_id, NULL, 10);

        if (id >= CONFIG_SEGMENT_COUNT) {
            return ESP_FAIL;
        }

        led_color[id][0] = MODE_WALK;
        led_color[id][1] = limit(payload[0]);
        led_color[id][2] = limit(payload[1]);
        led_color[id][3] = limit(payload[2]);

        ESP_LOGI("mqtt_handler", "set segment %d to walk color %d %d %d", id, led_color[id][1], led_color[id][2], led_color[id][3]);
    }

    if (!strcmp(topic + topic_len - buzzer_len, "/buzzer")) {
        if (length != 1) {
            return ESP_FAIL;
        }

        if (payload[0] == 0) {
            gpio_set_level(CONFIG_PIN_BUZZER, 0);
        } else {
            gpio_set_level(CONFIG_PIN_BUZZER, 1);
        }

        ESP_LOGI("mqtt_handler", "set buzzer to %d", payload[0]);
    }

    if (!strcmp(topic + topic_len - sync_len, "/sync")) {
        uint64_t time = esp_timer_get_time();
        last_time_blink = time;
        last_time_pulse = time;
        last_time_walk_fill = time;

        value_blink = 0;
        value_pulse = 0;
        value_walk_fill = 0;
        direction_pulse = 0;

        ESP_LOGI("mqtt_handler", "sync");
    }

    if (!strcmp(topic + topic_len - clear_len, "/clear")) {

        ESP_ERROR_CHECK(led_strip_clear(led_strip));
//        ESP_ERROR_CHECK(led_strip_refresh(led_strip));

        for (int i = 0; i < CONFIG_SEGMENT_COUNT; i++) {
            led_color[i][0] = MODE_OFF;
            led_color[i][1] = 0;
            led_color[i][2] = 0;
            led_color[i][3] = 0;
        }

        ESP_LOGI("mqtt_handler", "clear");
    }
    ESP_LOGI("mqtt_handler", "topic: %s", topic);
    return ESP_OK;
}


_Noreturn void app_main(void) {
    init_led_strip();

    ESP_ERROR_CHECK(led_strip_set_pixel(debug_led, 0, LIMIT, 0, 0));
    ESP_ERROR_CHECK(led_strip_refresh(debug_led));

    init_gpio();
    init_eventloop();
    init_nvs();
    init_wifi();

    while (1) {
        if (esp_timer_get_time() > last_time_blink + refresh_blink) {
            last_time_blink = esp_timer_get_time();
            value_blink = value_blink == 0 ? 1 : 0;

            for (int  i = 0; i < CONFIG_SEGMENT_COUNT; i++) {
                if (led_color[i][0] == MODE_BLINK) {
                    for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                        ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i * CONFIG_SEGMENT_SIZE + e, led_color[i][1] * value_blink, led_color[i][2] * value_blink,
                                             led_color[i][3] * value_blink));
                    }
                }
            }
            ESP_ERROR_CHECK(led_strip_refresh(led_strip));
        }

        // PULSE
        if (esp_timer_get_time() > last_time_pulse + refresh_pulse) {
            last_time_pulse = esp_timer_get_time();

            if (direction_pulse == 0) {
                value_pulse--;
                if (value_pulse <= 0) {
                    direction_pulse = 1;
                }
            } else {
                value_pulse++;
                if (value_pulse >= 255) {
                    direction_pulse = 0;
                }
            }

            for (int i = 0; i < CONFIG_SEGMENT_COUNT; i++) {
                if (led_color[i][0] == MODE_PULSE) {
                    for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                        ESP_ERROR_CHECK(led_strip_set_pixel(led_strip,
                                                            i * CONFIG_SEGMENT_SIZE + e,
                                                            (value_pulse * led_color[i][1]) / 255,
                                                            (value_pulse * led_color[i][2]) / 255,
                                                            (value_pulse * led_color[i][3]) / 255));
                    }
                }
            }
            ESP_ERROR_CHECK(led_strip_refresh(led_strip));
        }

        // WALK or FILL
        if (esp_timer_get_time() > last_time_walk_fill + refresh_walk_fill) {
            last_time_walk_fill = esp_timer_get_time();

            if (value_walk_fill >= CONFIG_SEGMENT_COUNT) {
                value_walk_fill = 0;
                for (int i = 0; i < CONFIG_SEGMENT_COUNT; i++) {
                    if (led_color[i][0] == MODE_FILL) {
                        for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                            ESP_ERROR_CHECK(led_strip_set_pixel(led_strip,
                                                                i * CONFIG_SEGMENT_SIZE + e,
                                                                0,
                                                                0,
                                                                0));
                        }
                    }
                }
            } else {
                value_walk_fill++;
                if (value_walk_fill == CONFIG_SEGMENT_COUNT) {
                    for (int i = 0; i < CONFIG_SEGMENT_COUNT; i++) {
                        if (led_color[i][0] == MODE_FILL) {
                            for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                                ESP_ERROR_CHECK(led_strip_set_pixel(led_strip,
                                                                    i * CONFIG_SEGMENT_SIZE + e,
                                                                    0,
                                                                    0,
                                                                    0));
                            }
                        }
                    }
                }
            }

            if (led_color[value_walk_fill][0] == MODE_FILL || led_color[value_walk_fill][0] == MODE_WALK) {
                for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                    ESP_ERROR_CHECK(led_strip_set_pixel(led_strip,
                                                        value_walk_fill * CONFIG_SEGMENT_SIZE + e,
                                                        led_color[value_walk_fill][1],
                                                        led_color[value_walk_fill][2],
                                                        led_color[value_walk_fill][3]));
                }
            }

            if (value_walk_fill > 0 && led_color[value_walk_fill - 1][0] == MODE_WALK) {
                for (int e = 0; e < CONFIG_SEGMENT_SIZE; e++) {
                    ESP_ERROR_CHECK(led_strip_set_pixel(led_strip,
                                                        value_walk_fill - 1 * CONFIG_SEGMENT_SIZE + e,
                                                        0,
                                                        0,
                                                        0));
                }
            }
            ESP_ERROR_CHECK(led_strip_refresh(led_strip));

        }
    }

}
