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

#define AUDIO_BASE_URL "https://fcrs-1367068685.cos.ap-guangzhou.myqcloud.com/car/audio/"

static const char *s_audio_files[] = {
    "noCameraDetected.mp3",
    "connectionFailed.mp3",
    "connectionSuccessful.mp3",
    "scanSuccessful.mp3",
    "toScanQRCode.mp3"
};

// 检查命令是否存在 (前置声明)
static int is_command_available(const char *cmd);

// 播放 ~/audio/ 下的音频文件
// 播放 ~/audio/ 下的音频文件，如果不存在则回退系统音
void play_audio_file(const char *filename) {
    char cmd[512];
    const char *audio_dir = "/home/orangepi/audio"; // 固定路径

    char filepath[256];
    snprintf(filepath, sizeof(filepath), "%s/%s", audio_dir, filename);

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

    // 1. 检查自定义文件是否存在
    if (access(filepath, F_OK) == 0) {
        // 文件存在，优先使用 ffplay
        if (is_command_available("ffplay")) {
            snprintf(cmd, sizeof(cmd), "ffplay -nodisp -autoexit -loglevel quiet \"%s\"", filepath);
            if (system(cmd) == 0) {
                my_zlog_debug("ffplay 播放成功");
                return;
            }
        }
        // 其次 paplay
        if (is_command_available("paplay")) {
            snprintf(cmd, sizeof(cmd), "paplay \"%s\"", filepath);
            if (system(cmd) == 0) {
                my_zlog_debug("paplay 播放成功");
                return;
            }
        }
        my_zlog_warn("自定义音频播放失败，尝试回退系统音...");
    } else {
        my_zlog_warn("音频文件 %s 不存在，准备播放系统回退音。", filepath);
    }

    // 2. 文件不存在，或者播放工具缺失 -> 回退到系统默认声音
    // 根据文件名映射一下大概的系统音
    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_audio_files() {
    const char *audio_dir = "/home/orangepi/audio"; // 固定路径

    // 1. 检查并创建目录
    struct stat st = {0};
    if (stat(audio_dir, &st) == -1) {
        my_zlog_info("正在创建音频目录: %s", audio_dir);
        mkdir(audio_dir, 0755);
    }

    // 2. 检查并下载每个文件
    for (int i = 0; i < 5; i++) {
        char filepath[512];
        snprintf(filepath, sizeof(filepath), "%s/%s", audio_dir, s_audio_files[i]);

        if (access(filepath, F_OK) != 0) {
            my_zlog_info("正在下载音频文件: %s", s_audio_files[i]);
            char cmd[1024];
            // 使用 wget -q (安静模式) -P (指定目录)
            snprintf(cmd, sizeof(cmd), "wget -q -P \"%s\" \"%s%s\"", audio_dir, AUDIO_BASE_URL, s_audio_files[i]);
            
            if (system(cmd) != 0) {
                 my_zlog_warn("下载失败: %s", s_audio_files[i]);
            }
        } else {
            // my_zlog_debug("文件已存在: %s", s_audio_files[i]);
        }
    }
}

// 检查命令是否存在
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_info("所需依赖 (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();
}

// 尝试连接 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() {
    my_zlog_info("开始检查网络连接状态...");

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

    // 2. 检查网络
    if (has_internet_connection()) {
        my_zlog_info("网络连接正常，正在检查音频资源...");
        download_audio_files();
        return;
    }

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

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

    // 首次播放
    // play_audio_file("toScanQRCode.mp3"); // 改为进入循环后由定时逻辑触发（且会先检查网络）
    last_prompt_time = 0; // 设为 0，确保进入循环第一次就会满足 difftime > 10.0 并触发播放逻辑

    while (1) {
        // 0. 优先检查网络是否已恢复 (比如插上了网线)
        if (has_internet_connection()) {
             my_zlog_info("检测到网络已恢复，退出扫码模式。");
             // 补一声连接成功的提示，让用户知道好了
             play_audio_file("connectionSuccessful.mp3");
             download_audio_files();
             break;
        }

        // 1. 周期性播放提示音 (每 10 秒)
        time_t now = time(NULL);
        if (difftime(now, last_prompt_time) >= 10.0) {
            // 再检查一次，如果有网就不播了，避免干扰
            if (!has_internet_connection()) {
                play_audio_file("toScanQRCode.mp3");
            }
            last_prompt_time = now;
        }

        // 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);
            play_audio_file("noCameraDetected.mp3");
            sleep(10); // 失败后多睡一会儿
            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_info("解析成功，SSID: %s", ssid_item->valuestring);
                play_audio_file("scanSuccessful.mp3");

                if (try_connect_wifi(ssid_item->valuestring, pwd_item->valuestring)) {
                    my_zlog_info("WiFi 连接成功！");
                    download_audio_files();
                    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_info("配网流程结束。");
}
