#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "led_button.h"

static const char *TAG = "LED_BTN";

static led_pattern_t current_pattern = LED_OFF;
static bool button_previous_state = true;
static bool button_pressed_flag = false;
static int64_t last_toggle_time = 0;
static bool blink_state = false;

/* Long-press factory reset tracking */
static int64_t button_press_start_ms = 0;
static bool button_is_held = false;

static void set_led(bool red, bool green, bool blue)
{
    gpio_set_level(LED_GPIO_RED, red ? 1 : 0);
    gpio_set_level(LED_GPIO_GREEN, green ? 1 : 0);
    gpio_set_level(LED_GPIO_BLUE, blue ? 1 : 0);
}

void led_button_init(void)
{
    gpio_set_direction(LED_GPIO_RED, GPIO_MODE_OUTPUT);
    gpio_set_direction(LED_GPIO_GREEN, GPIO_MODE_OUTPUT);
    gpio_set_direction(LED_GPIO_BLUE, GPIO_MODE_OUTPUT);

    gpio_set_direction(BTN_GPIO_RETRY, GPIO_MODE_INPUT);
    gpio_set_pull_mode(BTN_GPIO_RETRY, GPIO_PULLUP_ONLY);

    set_led(false, false, false);
    button_previous_state = gpio_get_level(BTN_GPIO_RETRY);
    ESP_LOGI(TAG, "LED + Button initialized");
}

void led_set_pattern(led_pattern_t pattern)
{
    current_pattern = pattern;

    switch (pattern) {
    case LED_OFF:
        set_led(false, false, false);
        break;
    case LED_GREEN:
        set_led(false, true, false);
        break;
    case LED_RED:
        set_led(true, false, false);
        break;
    case LED_BLUE:
        set_led(false, false, true);
        break;
    case LED_GREEN_BLINK:
    case LED_RED_BLINK:
    case LED_BLUE_BLINK:
    case LED_BLUE_BLINK_SLOW:
    case LED_BLUE_BLINK_FAST:
        /* Toggle handled by led_button_tick(). Start off. */
        blink_state = false;
        last_toggle_time = esp_timer_get_time() / 1000;
        set_led(false, false, false);
        break;
    }
}

bool button_retry_pressed(void)
{
    bool current = gpio_get_level(BTN_GPIO_RETRY);

    if (button_previous_state && !current) {
        button_previous_state = current;
        ESP_LOGI(TAG, "Retry button pressed");
        return true;
    }

    button_previous_state = current;
    return false;
}

void led_button_tick(void)
{
    /* Factory reset long-press detection (GPIO0 = BOOT button) */
    bool btn_level = gpio_get_level(BTN_GPIO_RETRY);
    if (btn_level == 0) {  /* button pressed (active low with pull-up) */
        if (!button_is_held) {
            button_is_held = true;
            button_press_start_ms = esp_timer_get_time() / 1000;
        } else {
            int64_t held_ms = (esp_timer_get_time() / 1000) - button_press_start_ms;
            if (held_ms > 5000) {
                ESP_LOGW(TAG, "BOOT button held %lldms — factory reset!", held_ms);
                esp_err_t erase_err = nvs_flash_erase();
                if (erase_err != ESP_OK) {
                    ESP_LOGE(TAG, "NVS erase failed: %d", erase_err);
                }
                esp_restart();
            }
        }
    } else {
        button_is_held = false;
    }

    if (current_pattern != LED_GREEN_BLINK &&
        current_pattern != LED_RED_BLINK &&
        current_pattern != LED_BLUE_BLINK &&
        current_pattern != LED_BLUE_BLINK_SLOW &&
        current_pattern != LED_BLUE_BLINK_FAST) {
        return;
    }

    int64_t now = esp_timer_get_time() / 1000;
    int64_t interval = 200;
    switch (current_pattern) {
    case LED_RED_BLINK:
    case LED_BLUE_BLINK_FAST:
        interval = 100;
        break;
    case LED_BLUE_BLINK_SLOW:
        interval = 1000;
        break;
    default:
        break;
    }

    if (now - last_toggle_time >= interval) {
        last_toggle_time = now;
        blink_state = !blink_state;

        switch (current_pattern) {
        case LED_BLUE_BLINK:
        case LED_BLUE_BLINK_SLOW:
        case LED_BLUE_BLINK_FAST:
            set_led(false, false, blink_state);
            break;
        case LED_RED_BLINK:
            set_led(blink_state, false, false);
            break;
        case LED_GREEN_BLINK:
            set_led(false, blink_state, false);
            break;
        default:
            break;
        }
    }
}
