#include "wifi_autoconfig.h"
#include "main.h"
#include "http_config_mqtt.h"
#include "device_wifi_manager.h"
#include "audioplay.h"
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

#define WIFI_OFFLINE_RECOVERY_INTERVAL_SEC 40
#define WIFI_RECOVERY_SETTLE_SEC 5
#define WIFI_RECOVERY_MAX_SWITCH_ATTEMPTS 3

static const char *s_audio_files[] = {
    "noCameraDetected.mp3",
    "connectionFailed.mp3",
    "connectionSuccessful.mp3",
    "scanSuccessful.mp3",
    "toScanQRCode.mp3",
    "Speedupforoneminute.mp3",
};
#define AUDIO_FILE_COUNT (sizeof(s_audio_files) / sizeof(s_audio_files[0]))
/* COS 已上传 DrivingLevel1～15，预留至 30；未上传的级别下载失败则跳过 */
#define AUDIO_DRIVING_LEVEL_MAX 30

// 外语子目录（中文走旧平铺路径，不在此列表）
static const char *s_foreign_langs[] = {
    AUDIO_LANG_EN,
    AUDIO_LANG_JA,
    AUDIO_LANG_KO,
    AUDIO_LANG_ES,
};
#define FOREIGN_LANG_COUNT (sizeof(s_foreign_langs) / sizeof(s_foreign_langs[0]))

static int is_command_available(const char *cmd);
static int ensure_audio_dir(const char *dir);

static char s_current_lang[8] = AUDIO_LANG_ZH;

static int is_cn_lang(const char *lang) {
    return lang != NULL && (strcmp(lang, AUDIO_LANG_ZH) == 0 || strcmp(lang, "cn") == 0);
}

static int is_en_lang(const char *lang) {
    return lang != NULL &&
           (strcmp(lang, AUDIO_LANG_EN) == 0 || strcmp(lang, "en") == 0 || strcmp(lang, "EN") == 0);
}

static void audio_save_offline_language(void) {
    ensure_audio_dir(AUDIO_LOCAL_BASE);
    FILE *fp = fopen(AUDIO_OFFLINE_LANG_FILE, "w");
    if (fp == NULL) {
        my_zlog_warn("保存离线语言配置失败: %s", AUDIO_OFFLINE_LANG_FILE);
        return;
    }
    fprintf(fp, "%s\n", s_current_lang);
    fclose(fp);
    my_zlog_debug("离线语言已保存: %s", s_current_lang);
}

void audio_init_offline_language(void) {
    FILE *fp = fopen(AUDIO_OFFLINE_LANG_FILE, "r");
    if (fp == NULL) {
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_ZH);
        my_zlog_debug("离线语言配置不存在，默认中文");
        return;
    }

    char buf[16] = {0};
    if (fgets(buf, sizeof(buf), fp) == NULL) {
        fclose(fp);
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_ZH);
        return;
    }
    fclose(fp);
    buf[strcspn(buf, "\r\n")] = '\0';

    if (is_cn_lang(buf)) {
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_ZH);
    } else if (is_en_lang(buf)) {
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_EN);
    } else {
        for (size_t i = 0; i < FOREIGN_LANG_COUNT; i++) {
            if (strcmp(buf, s_foreign_langs[i]) == 0) {
                snprintf(s_current_lang, sizeof(s_current_lang), "%s", s_foreign_langs[i]);
                my_zlog_debug("离线语言已加载: %s", s_current_lang);
                return;
            }
        }
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_ZH);
        my_zlog_warn("离线语言配置无效: %s，回退中文", buf);
        return;
    }
    my_zlog_debug("离线语言已加载: %s", s_current_lang);
}

void audio_set_language(const char *lang_code) {
    if (lang_code == NULL || lang_code[0] == '\0') {
        return;
    }
    if (is_cn_lang(lang_code)) {
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_ZH);
        my_zlog_info("离线音频语言已切换为: 中文");
        audio_save_offline_language();
        return;
    }
    if (is_en_lang(lang_code)) {
        snprintf(s_current_lang, sizeof(s_current_lang), "%s", AUDIO_LANG_EN);
        my_zlog_debug("离线音频语言已切换为: %s", s_current_lang);
        audio_save_offline_language();
        return;
    }
    for (size_t i = 0; i < FOREIGN_LANG_COUNT; i++) {
        if (strcmp(lang_code, s_foreign_langs[i]) == 0) {
            snprintf(s_current_lang, sizeof(s_current_lang), "%s", lang_code);
            my_zlog_debug("离线音频语言已切换为: %s", s_current_lang);
            audio_save_offline_language();
            return;
        }
    }
    my_zlog_warn("未知语言代码: %s，保持当前语言: %s", lang_code, s_current_lang);
}

const char *audio_toggle_cn_en(void) {
    if (is_cn_lang(s_current_lang)) {
        audio_set_language(AUDIO_LANG_EN);
    } else {
        audio_set_language(AUDIO_LANG_ZH);
    }
    return s_current_lang;
}

const char *audio_get_language(void) {
    return s_current_lang;
}

static int ensure_audio_dir(const char *dir) {
    struct stat st = {0};
    if (stat(dir, &st) == 0) {
        return 0;
    }
    if (mkdir(dir, 0755) != 0) {
        my_zlog_warn("创建音频目录失败: %s", dir);
        return -1;
    }
    my_zlog_debug("已创建音频目录: %s", dir);
    return 0;
}

// 中文旧路径：/home/orangepi/audio/xxx.mp3
static void build_cn_filepath(char *filepath, size_t size, const char *filename) {
    snprintf(filepath, size, "%s/%s", AUDIO_LOCAL_BASE, filename);
}

// 外语子目录：/home/orangepi/audio/{lang}/xxx.mp3
static void build_lang_filepath(char *filepath, size_t size, const char *lang, const char *filename) {
    snprintf(filepath, size, "%s/%s/%s", AUDIO_LOCAL_BASE, lang, filename);
}

static int try_play_filepath(const char *filepath) {
    if (access(filepath, F_OK) != 0) {
        return 0;
    }
    if (audioplay_file_with_browser_preempt(filepath, 1.0) == 0) {
        my_zlog_debug("离线音频播放成功: %s", filepath);
        return 1;
    }
    my_zlog_warn("音频播放失败: %s", filepath);
    return 0;
}

// 播放离线本地音频（无网络场景；按 audio_get_language 选择中文或 EN）
void play_audio_file(const char *filename) {
    char cmd[512];
    char filepath[256];

    my_zlog_debug("尝试播放音频: %s (语言: %s)", filename, s_current_lang);

    if (is_cn_lang(s_current_lang)) {
        build_cn_filepath(filepath, sizeof(filepath), filename);
        if (try_play_filepath(filepath)) {
            return;
        }
        my_zlog_warn("中文音频不存在: %s，准备播放系统回退音。", filepath);
    } else {
        build_lang_filepath(filepath, sizeof(filepath), s_current_lang, filename);
        if (try_play_filepath(filepath)) {
            return;
        }
        build_cn_filepath(filepath, sizeof(filepath), filename);
        if (try_play_filepath(filepath)) {
            my_zlog_debug("外语音频缺失，已回退中文: %s", filepath);
            return;
        }
        my_zlog_warn("音频文件不存在 (%s 及中文回退路径)，准备播放系统回退音。",
                     s_current_lang);
    }
    const char *sys_sound = "dialog-information";
    if (strstr(filename, "noCamera")) sys_sound = "software-error";
    else if (strstr(filename, "Failed")) sys_sound = "dialog-error";
    else if (strstr(filename, "Success")) sys_sound = "service-login";
    else if (strstr(filename, "toScan")) sys_sound = "dialog-question";

    if (is_command_available("paplay")) {
        snprintf(cmd, sizeof(cmd), "paplay /usr/share/sounds/ubuntu/stereo/%s.ogg", sys_sound);
        if (system(cmd) == 0) {
            my_zlog_debug("系统音 (paplay-ubuntu) 播放成功: %s", sys_sound);
            return;
        }
        snprintf(cmd, sizeof(cmd), "paplay /usr/share/sounds/freedesktop/stereo/%s.oga", sys_sound);
        if (system(cmd) == 0) {
            my_zlog_debug("系统音 (paplay-freedesktop) 播放成功: %s", sys_sound);
            return;
        }
    }

    if (is_command_available("ffplay")) {
        snprintf(cmd, sizeof(cmd), "ffplay -nodisp -autoexit -loglevel quiet /usr/share/sounds/ubuntu/stereo/%s.ogg", sys_sound);
        if (system(cmd) == 0) {
           my_zlog_debug("系统音 (ffplay) 播放成功: %s", sys_sound);
           return;
        }
    }

    my_zlog_error("所有播放尝试均失败！");
}

static void download_cn_audio(const char *filename, int optional) {
    char filepath[512];
    build_cn_filepath(filepath, sizeof(filepath), filename);
    if (access(filepath, F_OK) == 0) {
        return;
    }

    my_zlog_debug("正在下载中文音频: %s", filename);
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "wget -q -P \"%s\" \"%s%s\"",
             AUDIO_LOCAL_BASE, AUDIO_COS_BASE, filename);
    if (system(cmd) != 0) {
        if (optional) {
            my_zlog_debug("中文音频暂未上传，跳过: %s", filename);
        } else {
            my_zlog_warn("下载失败 [zh]: %s", filename);
        }
    }
}

static void download_lang_audio(const char *lang, const char *filename) {
    char lang_dir[128];
    snprintf(lang_dir, sizeof(lang_dir), "%s/%s", AUDIO_LOCAL_BASE, lang);
    ensure_audio_dir(lang_dir);

    char filepath[512];
    build_lang_filepath(filepath, sizeof(filepath), lang, filename);
    if (access(filepath, F_OK) == 0) {
        return;
    }

    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "wget -q -P \"%s\" \"%s%s/%s\"",
             lang_dir, AUDIO_COS_BASE, lang, filename);
    if (system(cmd) != 0) {
        my_zlog_debug("预留语言音频暂未上传 [%s]: %s", lang, filename);
    } else {
        my_zlog_debug("已下载 [%s]: %s", lang, filename);
    }
}

// 下载音频：中文走旧平铺路径；外语走子目录（COS 未上传则跳过）
static void download_audio_files() {
    ensure_audio_dir(AUDIO_LOCAL_BASE);

    for (size_t i = 0; i < AUDIO_FILE_COUNT; i++) {
        download_cn_audio(s_audio_files[i], 0);
    }

    for (int level = 1; level <= AUDIO_DRIVING_LEVEL_MAX; level++) {
        char filename[48];
        snprintf(filename, sizeof(filename), "DrivingLevel%d.mp3", level);
        download_cn_audio(filename, 1);
    }

    for (size_t l = 0; l < FOREIGN_LANG_COUNT; l++) {
        const char *lang = s_foreign_langs[l];
        for (size_t i = 0; i < AUDIO_FILE_COUNT; i++) {
            download_lang_audio(lang, s_audio_files[i]);
        }
        for (int level = 1; level <= AUDIO_DRIVING_LEVEL_MAX; level++) {
            char filename[48];
            snprintf(filename, sizeof(filename), "DrivingLevel%d.mp3", level);
            download_lang_audio(lang, filename);
        }
    }
}

// 有网后：先 getConfig 定区域语言，再下载离线音频（在其它语音播放之前）
static void prepare_offline_audio_after_network(void) {
    if (device_fetch_region_language() != 0) {
        my_zlog_warn("拉取区域语言失败，使用本地已保存语言: %s", audio_get_language());
    }
    download_audio_files();
}

// 检查命令是否存在
static int is_command_available(const char *cmd) {
    char check_cmd[256];
    snprintf(check_cmd, sizeof(check_cmd), "which %s > /dev/null 2>&1", cmd);
    return system(check_cmd) == 0;
}

// 检查并安装依赖
static void check_and_install_dependencies() {
    int need_install = 0;
    char packages[256] = "";
    
    // 检查拍照工具
    if (!is_command_available("fswebcam")) {
        my_zlog_warn("未检测到 fswebcam，准备安装...");
        strcat(packages, " fswebcam");
        need_install = 1;
    }

    // 检查扫码工具 (zbarimg 包含在 zbar-tools 中)
    if (!is_command_available("zbarimg")) {
        my_zlog_warn("未检测到 zbar-tools，准备安装...");
        strcat(packages, " zbar-tools");
        need_install = 1;
    }
    
    // 检查音频工具
    int has_audio_tool = 0;
    if (is_command_available("paplay") || is_command_available("ffplay")) {
        has_audio_tool = 1;
    }

    if (!has_audio_tool) {
        my_zlog_warn("未检测到 paplay 或 ffplay，准备安装 pulseaudio-utils...");
        // 只有在没音频工具时才安装
        strcat(packages, " pulseaudio-utils");
        need_install = 1;
    }

    if (need_install) {
        my_zlog_info("正在尝试自动安装依赖: %s (需要 sudo 权限)...", packages);
        
        char install_cmd[512];
        snprintf(install_cmd, sizeof(install_cmd), "sudo apt-get update && sudo apt-get install -y %s", packages);

        int ret = system(install_cmd);
        if (ret == 0) {
            my_zlog_info("依赖安装成功！");
        } else {
            my_zlog_error("依赖安装失败，自动配网功能可能无法正常使用。");
        }
    } else {
         my_zlog_debug("所需依赖 (fswebcam, zbar-tools, audio) 已就绪。");
    }
}

// HTTP 204 保底探测：用于 ping 被屏蔽时的应用层联网判断
static int has_http_204_connection() {
    // 先尝试 curl
    if (is_command_available("curl")) {
        int ret = system("test \"$(curl -sL --max-time 3 -o /dev/null -w '%{http_code}' https://connectivitycheck.gstatic.com/generate_204)\" = \"204\"");
        if (ret == 0) {
            my_zlog_debug("网络探测成功: HTTP 204 (curl, https)");
            return 1;
        }

        // 备用 HTTP，适配部分 HTTPS 证书链异常场景
        ret = system("test \"$(curl -sL --max-time 3 -o /dev/null -w '%{http_code}' http://connectivitycheck.gstatic.com/generate_204)\" = \"204\"");
        if (ret == 0) {
            my_zlog_debug("网络探测成功: HTTP 204 (curl, http)");
            return 1;
        }
    }

    // curl 不可用时，使用 wget 做兜底探测
    if (is_command_available("wget")) {
        int ret = system("wget -q --timeout=3 --spider https://connectivitycheck.gstatic.com/generate_204");
        if (ret == 0) {
            my_zlog_debug("网络探测成功: HTTP 204 (wget)");
            return 1;
        }
    }

    return 0;
}

// 业务接口保底探测：请求 getConfig，若返回 data 非空则视为联网可用
static int has_business_api_connection() {
    const char *device_no_raw = device_id_function();
    if (device_no_raw == NULL || device_no_raw[0] == '\0') {
        return 0;
    }

    // 设备号文件可能带换行，先清理
    char device_no[64];
    snprintf(device_no, sizeof(device_no), "%s", device_no_raw);
    device_no[strcspn(device_no, "\r\n")] = '\0';
    if (device_no[0] == '\0') {
        return 0;
    }

    if (is_command_available("curl")) {
        char cmd[512];
        snprintf(cmd, sizeof(cmd),
                 "curl -sL --max-time 3 \"https://fcrs-api.yd-ss.com/device/getConfig?deviceNo=%s\"",
                 device_no);

        FILE *fp = popen(cmd, "r");
        if (fp != NULL) {
            char resp[1024];
            size_t n = fread(resp, 1, sizeof(resp) - 1, fp);
            resp[n] = '\0';
            pclose(fp);

            cJSON *json = cJSON_Parse(resp);
            if (json != NULL) {
                cJSON *data = cJSON_GetObjectItemCaseSensitive(json, "data");
                if (data != NULL && !cJSON_IsNull(data)) {
                    my_zlog_debug("网络探测成功: business api");
                    cJSON_Delete(json);
                    return 1;
                }
                cJSON_Delete(json);
            }
        }
    }

    return 0;
}

// 检测是否有互联网连接（多目标 ping + HTTP 204 保底，任意成功即视为有网）
static int has_internet_connection() {
    static const char *targets[] = {
        "baidu.com",     // 国内常见目标
        "google.com",    // 海外常见目标
        "mqtt177.controlmelive.com", // 业务域名探测
        "47.83.167.0",   // 业务 IP 探测（不依赖 DNS）
        "1.1.1.1",       // Cloudflare DNS（不依赖域名解析）
        "8.8.8.8",        // Google DNS（不依赖域名解析） 
    };

    // -c 1: 发送 1 个包, -W 2: 超时 2 秒
    for (size_t i = 0; i < sizeof(targets) / sizeof(targets[0]); i++) {
        char cmd[256];
        snprintf(cmd, sizeof(cmd), "ping -c 1 -W 2 %s > /dev/null 2>&1", targets[i]);
        if (system(cmd) == 0) {
            my_zlog_debug("网络探测成功: %s", targets[i]);
            return 1; // 任意一个成功，直接返回
        }
    }

    // ping 全失败时，尝试应用层保底探测
    if (has_http_204_connection()) {
        return 1;
    }
    return has_business_api_connection();
}

/* 一次完整的断网恢复周期：播报与扫描主动连接必须在同一个周期执行。 */
static int run_offline_recovery_cycle(void) {
    my_zlog_warn("断网恢复: 开始 40 秒周期播报和已保存 WiFi 检测");
    play_audio_file("connectionFailed.mp3");

    for (int attempt = 0; attempt < WIFI_RECOVERY_MAX_SWITCH_ATTEMPTS; attempt++) {
        int connect_result = device_wifi_connect_best_saved_visible();
        if (connect_result <= 0)
            break;

        sleep(WIFI_RECOVERY_SETTLE_SEC);
        if (has_internet_connection()) {
            my_zlog_info("断网恢复: 已恢复互联网连接");
            prepare_offline_audio_after_network();
            play_audio_file("connectionSuccessful.mp3");
            return 1;
        }
        my_zlog_warn("断网恢复: WiFi 已连接但互联网仍不可用，继续尝试其它已保存网络");
    }

    return 0;
}

void *thread_wifi_offline_recovery(void *arg) {
    (void)arg;
    my_zlog_info("断网恢复线程已启动，检测间隔=%d秒",
                 WIFI_OFFLINE_RECOVERY_INTERVAL_SEC);

    while (1) {
        time_t cycle_started = time(NULL);
        if (!has_internet_connection())
            run_offline_recovery_cycle();

        time_t cycle_finished = time(NULL);
        int elapsed = (int)difftime(cycle_finished, cycle_started);
        int remaining = WIFI_OFFLINE_RECOVERY_INTERVAL_SEC - elapsed;
        if (remaining > 0)
            sleep((unsigned int)remaining);
    }
    return NULL;
}

// 尝试连接 WiFi
static int try_connect_wifi(const char *ssid, const char *password) {
    char cmd[512];
    // 使用 nmcli 连接，成功会自动保存为默认
    snprintf(cmd, sizeof(cmd), "nmcli dev wifi connect \"%s\" password \"%s\"", ssid, password);
    my_zlog_info("正在尝试连接 WiFi: %s ...", ssid);
    return system(cmd) == 0;
}

// 自动配网主逻辑
void check_and_autoconfig_wifi() {
    audio_init_offline_language();
    my_zlog_debug("开始检查网络连接状态...");

    // 1. 检查并处理依赖
    check_and_install_dependencies();

    // 2. 检查网络
    if (has_internet_connection()) {
        my_zlog_info("网络连接正常，正在确定区域语言并检查音频资源...");
        prepare_offline_audio_after_network();
        return;
    }

    my_zlog_warn("无法连接互联网，进入扫码配网模式 (拍照方案)。");
    my_zlog_warn("进入扫码循环，将每隔几秒提示一次...");

    const char *img_path = "/tmp/wifi_scan.jpg";
    time_t last_recovery_time = 0;
    time_t last_camera_warning_time = 0;

    while (1) {
        time_t now = time(NULL);
        if (last_recovery_time == 0 ||
            difftime(now, last_recovery_time) >= WIFI_OFFLINE_RECOVERY_INTERVAL_SEC) {
            /* 从本轮开始计时，保证两轮检测启动时间约间隔 40 秒。 */
            last_recovery_time = now;
            if (has_internet_connection()) {
                my_zlog_info("检测到网络已恢复，退出扫码模式。");
                prepare_offline_audio_after_network();
                play_audio_file("connectionSuccessful.mp3");
                break;
            }
            if (run_offline_recovery_cycle())
                break;
        }

        // 2. 调用 fswebcam 拍照
        // -r 640x480: 分辨率
        // --no-banner: 不加时间戳条
        // -S 2: 跳过前2帧(预热), 防止黑屏
        // -q: 静默模式
        char cap_cmd[256];
        snprintf(cap_cmd, sizeof(cap_cmd), "fswebcam -r 1280x720 --no-banner -S 2 -q %s > /dev/null 2>&1", img_path);
        
        int cap_ret = system(cap_cmd);
        if (cap_ret != 0) {
            // 拍照失败，通常意味着没插摄像头或设备忙
            my_zlog_error("摄像头拍照失败 (fswebcam 返回 %d)，请检查设备连接。", cap_ret);
            now = time(NULL);
            if (last_camera_warning_time == 0 ||
                difftime(now, last_camera_warning_time) >= WIFI_OFFLINE_RECOVERY_INTERVAL_SEC) {
                play_audio_file("noCameraDetected.mp3");
                last_camera_warning_time = now;
            }
            sleep(5);
            continue;
        }

        // 3. 调用 zbarimg 识别图片
        char scan_cmd[256];
        snprintf(scan_cmd, sizeof(scan_cmd), "zbarimg --raw -q %s", img_path);
        
        FILE *pipe = popen(scan_cmd, "r");
        if (!pipe) {
            my_zlog_error("无法执行 zbarimg！");
            sleep(2);
            continue;
        }

        char buffer[1024];
        int scan_success = 0;

        // zbarimg 输出即为识别结果 (可能有多行，我们只读第一行有效的)
        while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
            buffer[strcspn(buffer, "\r\n")] = 0;
            if (strlen(buffer) == 0) continue;

            my_zlog_debug("识别到内容: %s", buffer);

            cJSON *json = cJSON_Parse(buffer);
            if (!json) continue;

            cJSON *ssid_item = cJSON_GetObjectItemCaseSensitive(json, "s");
            cJSON *pwd_item = cJSON_GetObjectItemCaseSensitive(json, "p");

            if (cJSON_IsString(ssid_item) && ssid_item->valuestring &&
                cJSON_IsString(pwd_item) && pwd_item->valuestring) {
                
                my_zlog_debug("解析成功，SSID: %s", ssid_item->valuestring);
                play_audio_file("scanSuccessful.mp3");

                if (try_connect_wifi(ssid_item->valuestring, pwd_item->valuestring)) {
                    my_zlog_info("WiFi 连接成功！");
                    prepare_offline_audio_after_network();
                    play_audio_file("connectionSuccessful.mp3");
                    cJSON_Delete(json);
                    scan_success = 1;
                    break;
                } else {
                    my_zlog_warn("WiFi 连接失败");
                    play_audio_file("connectionFailed.mp3");
                }
            }
            cJSON_Delete(json);
        }
        pclose(pipe);

        if (scan_success) break;

        // 没扫到码，等待一小会儿再拍下一张，避免 CPU 占用过高
        // 不需要 sleep 太久，因为 fswebcam 启动本身就有开销(约0.5-1s)，这就已经是天然的延迟了
        usleep(500000); // 0.5秒
    }
    
    // 清理临时文件
    unlink(img_path);
    my_zlog_debug("配网流程结束。");
}
