#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_console.h"
#include "linenoise/linenoise.h"
#include "esp_spiffs.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "cmd_system.h"
#include "cmd_wifi.h"
#include "cmd_nvs.h"
#include "console_settings.h"
#include "cmd_iot_demo.h"

static const char *TAG = "app_main";
#define PROMPT_STR CONFIG_IDF_TARGET

#if CONFIG_CONSOLE_STORE_HISTORY
#define MOUNT_PATH "/data"
#define HISTORY_PATH MOUNT_PATH "/history.txt"
#else
#define MOUNT_PATH "/data"
#define HISTORY_PATH NULL
#endif // CONFIG_CONSOLE_STORE_HISTORY

#define AUDIO_TEST_FILE MOUNT_PATH "/aitalk_send_audio.wav"

static void initialize_filesystem(void)
{
    esp_vfs_spiffs_conf_t conf = {
        .base_path = MOUNT_PATH,
        .partition_label = "storage",
        .max_files = 5,
        .format_if_mount_failed = false,
    };
    esp_err_t err = esp_vfs_spiffs_register(&conf);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to mount SPIFFS (%s)", esp_err_to_name(err));
        return;
    }

    size_t total = 0, used = 0;
    esp_spiffs_info("storage", &total, &used);
    ESP_LOGI(TAG, "SPIFFS: total=%zu used=%zu", total, used);

    struct stat st;
    if (stat(AUDIO_TEST_FILE, &st) == 0) {
        ESP_LOGI(TAG, "Found %s (%ld bytes)", AUDIO_TEST_FILE, (long)st.st_size);
    } else {
        ESP_LOGW(TAG, "%s not found", AUDIO_TEST_FILE);
    }
}

static void initialize_nvs(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
}

void app_main(void)
{
    initialize_nvs();

#if CONFIG_CONSOLE_STORE_HISTORY
    initialize_filesystem();
    ESP_LOGI(TAG, "Command history enabled");
#else
    initialize_filesystem();
    ESP_LOGI(TAG, "Command history disabled");
#endif

    initialize_console_peripheral();
    initialize_console_library(HISTORY_PATH);

    const char *prompt = setup_prompt(PROMPT_STR ">");

    /* Register commands */
    esp_console_register_help_command();
    register_system();
    register_wifi();
    register_nvs();
    register_iot_demo_commands();

    /* Auto-connect WiFi from NVS (non-blocking) */
    wifi_auto_connect_from_nvs();

    printf("\n"
           "IoT  Console. Type 'help' for available commands.\n"
           "Use UP/DOWN arrows to navigate history. TAB to auto-complete.\n");

    if (linenoiseIsDumbMode()) {
        printf("\n"
               "Your terminal does not support escape sequences.\n"
               "Line editing and history features are disabled.\n");
    }

    /* Main loop */
    while (true) {
        char *line = linenoise(prompt);
        if (line == NULL) {
            continue;
        }

        if (strlen(line) > 0) {
            linenoiseHistoryAdd(line);
#if CONFIG_CONSOLE_STORE_HISTORY
            linenoiseHistorySave(HISTORY_PATH);
#endif
        }

        int ret;
        esp_err_t err = esp_console_run(line, &ret);
        if (err == ESP_ERR_NOT_FOUND) {
            printf("Unrecognized command\n");
        } else if (err == ESP_ERR_INVALID_ARG) {
            // empty command
        } else if (err == ESP_OK && ret != ESP_OK) {
            printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
        } else if (err != ESP_OK) {
            printf("Internal error: %s\n", esp_err_to_name(err));
        }
        linenoiseFree(line);
    }

    ESP_LOGE(TAG, "Error or end-of-input, terminating console");
    esp_console_deinit();
}
