#include <stdbool.h>

#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"

#include "wifi_provisioning.h"
#include "frame_client.h"
#include "next_button.h"
#include "back_button.h"
#include "combo_button.h"

static const char *TAG = "main";

void app_main(void)
{
    /* Redirected/invalid captive-portal traffic generates a lot of noise
     * at the default log level. */
    esp_log_level_set("httpd_uri", ESP_LOG_ERROR);
    esp_log_level_set("httpd_txrx", ESP_LOG_ERROR);
    esp_log_level_set("httpd_parse", ESP_LOG_ERROR);

    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    esp_err_t nvs_err = nvs_flash_init();
    if (nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        nvs_err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(nvs_err);

    /* Arms all three buttons as deep-sleep wakeup sources (so holding one
     * wakes the device promptly, not just during its brief awake
     * windows), then checks them -- covers both "held while asleep, just
     * woke us up" and "held while powering on" the same way, since both
     * look identical from here: the pin is just low right now. */
    next_button_init();
    back_button_init();
    combo_button_init();

    bool next_pressed = next_button_check();
    bool back_pressed = back_button_check();
    /* Next takes priority over back if somehow both read pressed at once
     * (e.g. both held through a power-on) -- an arbitrary but
     * deterministic tie-break, not expected to matter in practice. */
    fetch_action_t action = next_pressed ? FETCH_ADVANCE : back_pressed ? FETCH_BACK : FETCH_NORMAL;
    /* Soft-resets or clears config + restarts internally for a medium/
     * long hold and never returns in those cases -- only returns here
     * for "not pressed" (false) or "quick press" (true, show the menu). */
    bool show_management_qr = combo_button_check();

    frame_config_t cfg;
    esp_err_t cfg_err = frame_config_load(&cfg);
    if (cfg_err == ESP_OK) {
        ESP_LOGI(TAG, "Found stored config for '%s', connecting to home WiFi", cfg.sta_ssid);
        if (frame_wifi_connect_sta(&cfg) == ESP_OK) {
            frame_client_run(&cfg, action, show_management_qr);
            return; /* frame_client_run currently never returns */
        }
        ESP_LOGW(TAG, "Could not connect to stored WiFi after %d attempts, falling back to provisioning",
                 CONFIG_FRAME_STA_CONNECT_MAX_RETRIES);
    } else {
        ESP_LOGI(TAG, "No stored config found (%s), starting provisioning", esp_err_to_name(cfg_err));
    }

    wifi_provisioning_start();
}
