#include "device_identity.h"
#include "device_wifi_change.h"
#include "device_wifi_manager.h"
#include "modules_common.h"

#define MAX_WIFI_ENTRIES 32
#define MAX_SAVED_WIFI_SLOTS 10
#define SSID_MAX_LENGTH 64
#define WIFI_PSK_MAX_LENGTH 63
#define NM_CONN_DIR "/etc/NetworkManager/system-connections/"

static ThreadPool_t *s_wifi_pool = NULL;
static pthread_mutex_t s_wifi_pool_mutex = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
    char ssid[SSID_MAX_LENGTH];
    time_t mtime;
} saved_wifi_entry_t;

typedef struct {
    char ssid[SSID_MAX_LENGTH];
    char password[WIFI_PSK_MAX_LENGTH + 1];
} wifi_save_task_t;

typedef struct {
    char ssid[SSID_MAX_LENGTH];
} wifi_delete_task_t;

static void wifi_save_worker(void *arg);
static void wifi_delete_worker(void *arg);
static int submit_wifi_task(void (*worker)(void *), void *arg, const char *what);

static int is_default_wifi_ssid(const char *ssid) {
    return ssid != NULL && strcmp(ssid, default_SSID) == 0;
}

static int entry_index_by_name(const saved_wifi_entry_t *entries, int count,
                               const char *name) {
    for (int i = 0; i < count; i++) {
        if (strcmp(entries[i].ssid, name) == 0)
            return i;
    }
    return -1;
}

static void trim_line(char *line) {
    size_t n;

    if (!line)
        return;
    n = strcspn(line, "\r\n");
    line[n] = '\0';
}

static int read_profile_id(const char *filepath, char *id_out, size_t id_size) {
    FILE *fp;
    char line[256];

    fp = fopen(filepath, "r");
    if (!fp)
        return -1;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        if (strncmp(line, "id=", 3) == 0) {
            strncpy(id_out, line + 3, id_size - 1);
            id_out[id_size - 1] = '\0';
            fclose(fp);
            return id_out[0] ? 0 : -1;
        }
    }

    fclose(fp);
    return -1;
}

static int is_wifi_profile_file(const char *filepath) {
    FILE *fp;
    char line[256];

    fp = fopen(filepath, "r");
    if (!fp)
        return 0;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        if (strcmp(line, "type=wifi") == 0 ||
            strcmp(line, "type=802-11-wireless") == 0) {
            fclose(fp);
            return 1;
        }
    }

    fclose(fp);
    return 0;
}

static int is_wifi_connection_type(const char *type) {
    return type && (strcmp(type, "802-11-wireless") == 0 || strcmp(type, "wifi") == 0);
}

/* 解析 nmcli -t 一行：支持 name:device:type 与 name:type 两种格式 */
static int parse_nmcli_connection_line(const char *line, char *name, size_t name_sz,
                                       char *device, size_t dev_sz,
                                       char *type, size_t type_sz) {
    const char *c1;
    const char *c2;
    size_t len;

    if (!line || !name || !device || !type)
        return -1;

    name[0] = device[0] = type[0] = '\0';
    c1 = strchr(line, ':');
    if (!c1)
        return -1;

    len = (size_t)(c1 - line);
    if (len >= name_sz)
        len = name_sz - 1;
    memcpy(name, line, len);
    name[len] = '\0';

    c2 = strchr(c1 + 1, ':');
    if (!c2) {
        strncpy(type, c1 + 1, type_sz - 1);
        type[type_sz - 1] = '\0';
        trim_line(type);
        return 0;
    }

    len = (size_t)(c2 - c1 - 1);
    if (len >= dev_sz)
        len = dev_sz - 1;
    memcpy(device, c1 + 1, len);
    device[len] = '\0';

    strncpy(type, c2 + 1, type_sz - 1);
    type[type_sz - 1] = '\0';
    trim_line(type);
    return 0;
}

/* 无需读文件内容，stat 即可拿到 mtime（普通用户也可 stat root 600 文件） */
static time_t wifi_profile_mtime_from_disk(const char *ssid) {
    char path[512];
    struct stat st;
    DIR *dir;
    struct dirent *entry;
    time_t oldest = 0;
    size_t ssid_len;

    if (!ssid || !ssid[0])
        return 0;

    snprintf(path, sizeof(path), "%s%s.nmconnection", NM_CONN_DIR, ssid);
    if (stat(path, &st) == 0)
        oldest = st.st_mtime;

    ssid_len = strlen(ssid);
    dir = opendir(NM_CONN_DIR);
    if (!dir)
        return oldest;

    while ((entry = readdir(dir)) != NULL) {
        if (!strstr(entry->d_name, ".nmconnection"))
            continue;
        if (strncmp(entry->d_name, ssid, ssid_len) != 0)
            continue;
        if (entry->d_name[ssid_len] != '\0' &&
            entry->d_name[ssid_len] != '-' &&
            entry->d_name[ssid_len] != '.')
            continue;
        snprintf(path, sizeof(path), "%s%s", NM_CONN_DIR, entry->d_name);
        if (stat(path, &st) == 0 && (oldest == 0 || st.st_mtime < oldest))
            oldest = st.st_mtime;
    }

    closedir(dir);
    return oldest;
}

static void merge_wifi_entry(saved_wifi_entry_t *entries, int *count, int max_count,
                             const char *ssid, time_t mtime) {
    int idx;
    time_t mt;

    if (!ssid || !ssid[0] || !entries || !count)
        return;

    idx = entry_index_by_name(entries, *count, ssid);
    mt = mtime > 0 ? mtime : wifi_profile_mtime_from_disk(ssid);
    if (idx >= 0) {
        if (mt > 0 && (entries[idx].mtime == 0 || mt < entries[idx].mtime))
            entries[idx].mtime = mt;
        return;
    }
    if (*count >= max_count)
        return;

    strncpy(entries[*count].ssid, ssid, sizeof(entries[*count].ssid) - 1);
    entries[*count].ssid[sizeof(entries[*count].ssid) - 1] = '\0';
    entries[*count].mtime = mt;
    (*count)++;
}

static int collect_saved_wifi_entries_from_files(saved_wifi_entry_t *entries, int max_count) {
    DIR *dir;
    struct dirent *entry;
    int count = 0;

    dir = opendir(NM_CONN_DIR);
    if (!dir) {
        my_zlog_error("无法打开NetworkManager配置目录");
        return -1;
    }

    while ((entry = readdir(dir)) != NULL && count < max_count) {
        char filepath[512];
        char profile_id[SSID_MAX_LENGTH];
        struct stat st;

        if (entry->d_type != DT_REG && entry->d_type != DT_UNKNOWN)
            continue;
        if (!strstr(entry->d_name, ".nmconnection"))
            continue;

        snprintf(filepath, sizeof(filepath), "%s%s", NM_CONN_DIR, entry->d_name);
        if (!is_wifi_profile_file(filepath))
            continue;
        if (read_profile_id(filepath, profile_id, sizeof(profile_id)) != 0)
            continue;
        if (stat(filepath, &st) != 0)
            continue;
        {
            int idx = entry_index_by_name(entries, count, profile_id);
            if (idx >= 0) {
                if (st.st_mtime < entries[idx].mtime)
                    entries[idx].mtime = st.st_mtime;
                continue;
            }
        }

        strncpy(entries[count].ssid, profile_id, sizeof(entries[count].ssid) - 1);
        entries[count].ssid[sizeof(entries[count].ssid) - 1] = '\0';
        entries[count].mtime = st.st_mtime;
        count++;
    }

    closedir(dir);
    return count;
}

/* 以 nmcli 列表为准，兼容 name:type 两列输出 */
static int collect_saved_wifi_entries_from_nmcli(saved_wifi_entry_t *entries, int max_count) {
    FILE *fp;
    char line[256];
    char name[SSID_MAX_LENGTH];
    char device[64];
    char conn_type[64];
    int count = 0;

    fp = popen("nmcli -t -f NAME,TYPE connection show", "r");
    if (!fp)
        return 0;

    while (fgets(line, sizeof(line), fp) && count < max_count) {
        trim_line(line);
        if (!line[0])
            continue;
        if (parse_nmcli_connection_line(line, name, sizeof(name),
                                        device, sizeof(device),
                                        conn_type, sizeof(conn_type)) != 0)
            continue;
        if (!is_wifi_connection_type(conn_type))
            continue;

        {
            int idx = entry_index_by_name(entries, count, name);
            if (idx >= 0)
                continue;
        }

        strncpy(entries[count].ssid, name, sizeof(entries[count].ssid) - 1);
        entries[count].ssid[sizeof(entries[count].ssid) - 1] = '\0';
        entries[count].mtime = wifi_profile_mtime_from_disk(name);
        count++;
    }

    pclose(fp);
    return count;
}

static int collect_saved_wifi_entries(saved_wifi_entry_t *entries, int max_count) {
    saved_wifi_entry_t file_entries[MAX_WIFI_ENTRIES];
    saved_wifi_entry_t nmcli_entries[MAX_WIFI_ENTRIES];
    int count = 0;
    int file_count;
    int nmcli_count;

    file_count = collect_saved_wifi_entries_from_files(file_entries, MAX_WIFI_ENTRIES);
    if (file_count < 0)
        file_count = 0;
    for (int i = 0; i < file_count; i++)
        merge_wifi_entry(entries, &count, max_count, file_entries[i].ssid, file_entries[i].mtime);

    nmcli_count = collect_saved_wifi_entries_from_nmcli(nmcli_entries, MAX_WIFI_ENTRIES);
    for (int i = 0; i < nmcli_count; i++)
        merge_wifi_entry(entries, &count, max_count, nmcli_entries[i].ssid, nmcli_entries[i].mtime);

    return count;
}

static int nmcli_wifi_connection_exists(const char *ssid) {
    FILE *fp;
    char line[256];
    char name[SSID_MAX_LENGTH];
    char device[64];
    char conn_type[64];

    if (!ssid || !ssid[0])
        return 0;

    fp = popen("nmcli -t -f NAME,TYPE connection show", "r");
    if (!fp)
        return 0;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        if (parse_nmcli_connection_line(line, name, sizeof(name),
                                        device, sizeof(device),
                                        conn_type, sizeof(conn_type)) != 0)
            continue;
        if (!is_wifi_connection_type(conn_type))
            continue;
        if (strcmp(name, ssid) == 0) {
            pclose(fp);
            return 1;
        }
    }

    pclose(fp);
    return 0;
}

static int wifi_connection_exists(const char *ssid) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    if (count < 0)
        return nmcli_wifi_connection_exists(ssid);
    if (entry_index_by_name(entries, count, ssid) >= 0)
        return 1;
    return nmcli_wifi_connection_exists(ssid);
}

static int count_non_default_saved_wifi(void) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    if (count < 0)
        return -1;

    int non_default_count = 0;
    for (int i = 0; i < count; i++) {
        if (!is_default_wifi_ssid(entries[i].ssid))
            non_default_count++;
    }
    return non_default_count;
}

static int connection_is_active(const char *name) {
    FILE *fp;
    char line[256];
    char conn_name[SSID_MAX_LENGTH];
    char device[64];
    char conn_type[64];

    if (!name || !name[0])
        return 0;

    fp = popen("nmcli -t -f NAME,DEVICE,TYPE connection show", "r");
    if (!fp)
        return 0;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        if (parse_nmcli_connection_line(line, conn_name, sizeof(conn_name),
                                        device, sizeof(device),
                                        conn_type, sizeof(conn_type)) != 0)
            continue;
        if (strcmp(conn_name, name) != 0)
            continue;
        if (!is_wifi_connection_type(conn_type))
            continue;
        pclose(fp);
        return device[0] != '\0';
    }

    pclose(fp);
    return 0;
}

/* wlan0 当前绑定的连接配置名，与 .nmconnection 里 id= 一致 */
static void get_active_wifi_profile_name(char *name_out, size_t name_size) {
    FILE *fp;
    char line[256];
    char *value;

    if (!name_out || name_size == 0)
        return;
    name_out[0] = '\0';

    fp = popen("nmcli -t -f GENERAL.CONNECTION dev show wlan0", "r");
    if (!fp)
        return;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        if (strncmp(line, "GENERAL.CONNECTION:", 19) != 0)
            continue;
        value = line + 19;
        if (!value[0] || strcmp(value, "--") == 0)
            break;
        strncpy(name_out, value, name_size - 1);
        name_out[name_size - 1] = '\0';
        break;
    }

    pclose(fp);
}

static int wifi_profile_is_in_use(const char *ssid) {
    char active_profile[SSID_MAX_LENGTH];

    if (!ssid || !ssid[0])
        return 0;

    get_active_wifi_profile_name(active_profile, sizeof(active_profile));
    if (active_profile[0] && strcmp(ssid, active_profile) == 0)
        return 1;
    if (g_current_ssid[0] && strcmp(ssid, g_current_ssid) == 0)
        return 1;
    /* 仅当 DEVICE 非空才算在用，且兼容 name:type 两列输出 */
    return connection_is_active(ssid) != 0;
}

static int remove_wifi_profile_files(const char *ssid) {
    DIR *dir;
    struct dirent *entry;
    char filepath[512];
    char profile_id[SSID_MAX_LENGTH];
    int removed = 0;
    size_t ssid_len;

    if (!ssid || !ssid[0])
        return -1;

    ssid_len = strlen(ssid);
    snprintf(filepath, sizeof(filepath), "%s%s.nmconnection", NM_CONN_DIR, ssid);
    if (unlink(filepath) == 0)
        removed = 1;

    dir = opendir(NM_CONN_DIR);
    if (!dir)
        return removed ? 0 : -1;

    while ((entry = readdir(dir)) != NULL) {
        if (!strstr(entry->d_name, ".nmconnection"))
            continue;
        snprintf(filepath, sizeof(filepath), "%s%s", NM_CONN_DIR, entry->d_name);
        if (strncmp(entry->d_name, ssid, ssid_len) == 0 &&
            (entry->d_name[ssid_len] == '\0' ||
             entry->d_name[ssid_len] == '-' ||
             entry->d_name[ssid_len] == '.')) {
            if (unlink(filepath) == 0)
                removed = 1;
            continue;
        }
        if (read_profile_id(filepath, profile_id, sizeof(profile_id)) != 0)
            continue;
        if (strcmp(profile_id, ssid) != 0)
            continue;
        if (unlink(filepath) == 0)
            removed = 1;
    }

    closedir(dir);
    return removed ? 0 : -1;
}

/* 同名连接在 nmcli 里可能有多条，循环删到干净 */
static int delete_nmcli_connection_by_name(const char *ssid) {
    char command[280];
    int deleted = 0;

    if (!ssid || !ssid[0])
        return -1;

    for (int i = 0; i < 8; i++) {
        snprintf(command, sizeof(command),
                 "nmcli connection delete '%s' 2>/dev/null", ssid);
        if (system(command) != 0)
            break;
        deleted = 1;
    }

    return deleted ? 0 : -1;
}

/* 与 MQTT 2009 共用：删配置文件 + nmcli 连接（仅未在用的） */
static int device_wifi_delete_saved_profile(const char *ssid) {
    int file_rc;
    int nmcli_rc;

    if (!ssid || !ssid[0])
        return -1;
    if (is_default_wifi_ssid(ssid)) {
        my_zlog_warn("默认WiFi %s 不允许删除", default_SSID);
        return -2;
    }
    if (wifi_profile_is_in_use(ssid)) {
        my_zlog_warn("WiFi %s 正在使用，跳过删除", ssid);
        return -3;
    }

    file_rc = remove_wifi_profile_files(ssid);
    nmcli_rc = delete_nmcli_connection_by_name(ssid);
    if (file_rc == 0 || nmcli_rc == 0)
        return 0;

    my_zlog_error("删除WiFi失败(文件rc=%d, nmcli rc=%d): %s", file_rc, nmcli_rc, ssid);
    return -1;
}

/* 从最旧往新找：跳过默认 WiFi 与正在使用的配置 */
static int find_oldest_deletable_wifi(char *ssid_out, size_t ssid_size) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    int best = -1;

    if (count <= 0)
        return -1;

    for (int i = 0; i < count; i++) {
        if (is_default_wifi_ssid(entries[i].ssid))
            continue;
        if (wifi_profile_is_in_use(entries[i].ssid))
            continue;
        if (best < 0 || entries[i].mtime < entries[best].mtime)
            best = i;
    }

    if (best < 0)
        return -1;

    strncpy(ssid_out, entries[best].ssid, ssid_size - 1);
    ssid_out[ssid_size - 1] = '\0';
    return 0;
}

static int enforce_saved_wifi_limit(const char *new_ssid) {
    char oldest_ssid[SSID_MAX_LENGTH];
    int count;

    if (is_default_wifi_ssid(new_ssid) || wifi_connection_exists(new_ssid))
        return 0;

    for (int guard = 0; guard < MAX_WIFI_ENTRIES; guard++) {
        int rc;

        get_current_wifi();
        count = count_non_default_saved_wifi();
        if (count < 0)
            return -1;
        if (count < MAX_SAVED_WIFI_SLOTS)
            return 0;

        if (find_oldest_deletable_wifi(oldest_ssid, sizeof(oldest_ssid)) != 0) {
            my_zlog_error("非默认WiFi已满%d个，且无未在用的配置可删(当前非默认%d个)",
                          MAX_SAVED_WIFI_SLOTS, count);
            return -1;
        }

        rc = device_wifi_delete_saved_profile(oldest_ssid);
        if (rc == -3) {
            my_zlog_warn("最旧WiFi %s 正在使用，尝试删除下一旧配置", oldest_ssid);
            continue;
        }
        if (rc != 0) {
            my_zlog_error("删除最旧未使用WiFi失败: %s (rc=%d)", oldest_ssid, rc);
            return -1;
        }

        my_zlog_info("非默认WiFi已满%d个，删除最旧未使用配置: %s",
                     MAX_SAVED_WIFI_SLOTS, oldest_ssid);
    }

    my_zlog_error("非默认WiFi自动清理超过最大轮次");
    return -1;
}

static void chmod_wifi_profile_files(const char *ssid) {
    char path[512];
    DIR *dir;
    struct dirent *entry;
    char profile_id[SSID_MAX_LENGTH];

    snprintf(path, sizeof(path), "%s%s.nmconnection", NM_CONN_DIR, ssid);
    chmod(path, 0600);

    dir = opendir(NM_CONN_DIR);
    if (!dir)
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (!strstr(entry->d_name, ".nmconnection"))
            continue;
        snprintf(path, sizeof(path), "%s%s", NM_CONN_DIR, entry->d_name);
        if (read_profile_id(path, profile_id, sizeof(profile_id)) != 0)
            continue;
        if (strcmp(profile_id, ssid) == 0)
            chmod(path, 0600);
    }

    closedir(dir);
}

/* 与老代码一致：用 nmcli 保存，避免直接写文件触发 NM 重载 wlan0 */
static int save_wifi_via_nmcli(const char *ssid, const char *password) {
    char command[512];
    int ret;

    if (!wifi_connection_exists(ssid)) {
        snprintf(command, sizeof(command),
                 "nmcli connection add type wifi con-name '%s' ifname wlan0 ssid '%s'",
                 ssid, ssid);
        ret = system(command);
        if (ret != 0) {
            my_zlog_error("nmcli add 失败: %s (ret=%d)", ssid, ret);
            return -1;
        }
    }

    snprintf(command, sizeof(command),
             "nmcli connection modify '%s' connection.autoconnect no "
             "wifi-sec.key-mgmt wpa-psk wifi-sec.psk '%s'",
             ssid, password);
    ret = system(command);
    if (ret != 0) {
        my_zlog_error("nmcli modify 失败: %s (ret=%d)", ssid, ret);
        return -1;
    }

    chmod_wifi_profile_files(ssid);
    return 0;
}

static int validate_wifi_credentials(const char *ssid, const char *password) {
    if (!ssid || !password || strlen(ssid) == 0 || strlen(password) == 0) {
        my_zlog_error("SSID或密码为空");
        return -1;
    }
    if (strlen(ssid) >= SSID_MAX_LENGTH) {
        my_zlog_error("SSID过长");
        return -1;
    }
    if (strlen(password) > WIFI_PSK_MAX_LENGTH) {
        my_zlog_error("WiFi密码过长");
        return -1;
    }
    if (strpbrk(ssid, "\"`$|;\\") || strpbrk(password, "\"`$|;\\")) {
        my_zlog_error("WiFi凭据含非法字符");
        return -1;
    }
    return 0;
}

/*成功发送3010：0保存成功，1删除成功，2保存失败，3默认WiFi不可删，4删除失败*/
void device_wifi_public_sendmqtt(int wifi_status) {
    cJSON *root = cJSON_CreateObject();
    cJSON *body = cJSON_CreateObject();
    cJSON *head = cJSON_CreateObject();

    cJSON_AddNumberToObject(body, "wifi_status", wifi_status);
    cJSON_AddNumberToObject(head, "message_type", 3010);

    cJSON_AddItemToObject(root, "body", body);
    cJSON_AddItemToObject(root, "head", head);

    char *payload = cJSON_PrintUnformatted(root);
    my_zlog_debug("%s", payload);
    mqtt_publish_to_all(mqtt_topic_pure_number(), payload, 0);

    free(payload);
    cJSON_Delete(root);
}

int get_saved_wifi_list(char ssid_list[][SSID_MAX_LENGTH], int max_count) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int limit = max_count < MAX_WIFI_ENTRIES ? max_count : MAX_WIFI_ENTRIES;
    int count = collect_saved_wifi_entries(entries, limit);
    if (count < 0)
        return -1;

    for (int i = 0; i < count; i++) {
        strncpy(ssid_list[i], entries[i].ssid, SSID_MAX_LENGTH - 1);
        ssid_list[i][SSID_MAX_LENGTH - 1] = '\0';
    }

    return count;
}

int orange_pi_save_wifi(const char *ssid, const char *password) {
    if (validate_wifi_credentials(ssid, password) != 0)
        return -1;

    if (!wifi_connection_exists(ssid) && enforce_saved_wifi_limit(ssid) != 0)
        return -1;

    if (save_wifi_via_nmcli(ssid, password) != 0) {
        my_zlog_error("[ERROR] 保存配置失败: %s", ssid);
        return -1;
    }

    my_zlog_info("[SUCCESS] 已保存WiFi配置: %s", ssid);
    return 0;
}

int orange_pi_connect_wifi(const char *ssid, const char *password) {
    char command[512];
    int ret;

    if (!ssid || !ssid[0])
        return -1;

    if (password && password[0]) {
        if (validate_wifi_credentials(ssid, password) != 0)
            return -1;
    } else if (strlen(ssid) >= SSID_MAX_LENGTH || strpbrk(ssid, "\"`$|;\\")) {
        my_zlog_error("SSID无效");
        return -1;
    }

    if (!wifi_connection_exists(ssid) && enforce_saved_wifi_limit(ssid) != 0)
        return -1;

    if (password && password[0]) {
        snprintf(command, sizeof(command),
                 "nmcli device wifi connect '%s' password '%s'", ssid, password);
    } else {
        snprintf(command, sizeof(command), "nmcli device wifi connect '%s'", ssid);
    }

    ret = system(command);
    if (ret != 0) {
        my_zlog_error("nmcli connect 失败: %s (ret=%d)", ssid, ret);
        return -1;
    }

    my_zlog_info("[SUCCESS] 已连接WiFi: %s", ssid);
    return 0;
}

static int ensure_wifi_pool(void) {
    pthread_mutex_lock(&s_wifi_pool_mutex);
    if (!s_wifi_pool)
        s_wifi_pool = thread_pool_init(1, 1);
    pthread_mutex_unlock(&s_wifi_pool_mutex);
    return s_wifi_pool ? 0 : -1;
}

static void wifi_save_worker(void *arg) {
    wifi_save_task_t *task = arg;
    int rc;

    if (!task)
        return;
    rc = orange_pi_save_wifi(task->ssid, task->password);
    device_wifi_public_sendmqtt(rc == 0 ? 0 : 2);
    free(task);
}

static void wifi_delete_worker(void *arg) {
    wifi_delete_task_t *task = arg;
    int rc;

    if (!task)
        return;

    rc = device_wifi_delete_saved_profile(task->ssid);
    if (rc == 0) {
        my_zlog_info("删除成功");
        device_wifi_public_sendmqtt(1);
    } else if (rc == -2) {
        device_wifi_public_sendmqtt(3);
    } else {
        my_zlog_info("删除失败");
        device_wifi_public_sendmqtt(4);
    }
    free(task);
}

static int submit_wifi_task(void (*worker)(void *), void *arg, const char *what) {
    if (ensure_wifi_pool() != 0 || !s_wifi_pool) {
        my_zlog_error("%s: wifi thread pool init failed", what);
        free(arg);
        return -1;
    }
    if (thread_pool_add_task(s_wifi_pool, worker, arg) != 0) {
        my_zlog_error("%s: thread_pool_add_task failed", what);
        free(arg);
        return -1;
    }
    return 0;
}

void device_wifi_rec_sava(cJSON *body) {
    cJSON *wifi_ssid = cJSON_GetObjectItem(body, "wifi_ssid");
    cJSON *wifi_password = cJSON_GetObjectItem(body, "wifi_password");
    wifi_save_task_t *task;

    if (!cJSON_IsString(wifi_ssid) || !cJSON_IsString(wifi_password))
        return;

    task = calloc(1, sizeof(*task));
    if (!task) {
        device_wifi_public_sendmqtt(2);
        return;
    }
    strncpy(task->ssid, wifi_ssid->valuestring, sizeof(task->ssid) - 1);
    strncpy(task->password, wifi_password->valuestring, sizeof(task->password) - 1);
    my_zlog_debug("接收到保存WiFi，后台 nmcli 保存");
    if (submit_wifi_task(wifi_save_worker, task, "save wifi") != 0)
        device_wifi_public_sendmqtt(2);
}

void device_wifi_rec_delete(cJSON *body) {
    cJSON *wifi_ssid = cJSON_GetObjectItem(body, "wifi_ssid");
    wifi_delete_task_t *task;

    if (!cJSON_IsString(wifi_ssid))
        return;

    task = calloc(1, sizeof(*task));
    if (!task) {
        device_wifi_public_sendmqtt(4);
        return;
    }
    strncpy(task->ssid, wifi_ssid->valuestring, sizeof(task->ssid) - 1);
    my_zlog_debug("接收到删除WiFi，后台删配置文件: %s", task->ssid);
    if (submit_wifi_task(wifi_delete_worker, task, "delete wifi") != 0)
        device_wifi_public_sendmqtt(4);
}

void device_send_saved_wifi() {
    get_current_wifi();

    char list_wifi[MAX_WIFI_ENTRIES][SSID_MAX_LENGTH];
    int count = get_saved_wifi_list(list_wifi, MAX_WIFI_ENTRIES);
    if (count < 0) {
        my_zlog_error("读取已保存WiFi配置失败");
        return;
    }

    cJSON *root = cJSON_CreateObject();
    cJSON *body = cJSON_CreateObject();
    cJSON *head = cJSON_CreateObject();
    cJSON_AddStringToObject(body, "current_connected", g_current_ssid[0] ? g_current_ssid : "");
    cJSON *array = cJSON_CreateArray();
    for (int i = 0; i < count; i++) {
        cJSON *item = cJSON_CreateObject();
        my_zlog_debug("%d. %s\n", i + 1, list_wifi[i]);
        cJSON_AddStringToObject(item, "ssid", list_wifi[i]);
        cJSON_AddItemToArray(array, item);
    }
    cJSON_AddItemToObject(body, "available_wifi", array);
    cJSON_AddNumberToObject(head, "message_type", 3012);
    cJSON_AddItemToObject(root, "body", body);
    cJSON_AddItemToObject(root, "head", head);

    char *json_str = cJSON_Print(root);
    if (json_str) {
        my_zlog_debug("%s", json_str);
        mqtt_publish_to_all(mqtt_topic_pure_number(), json_str, 0);
        free(json_str);
    }
    cJSON_Delete(root);
}

/* ==================== App WiFi 管理 (UDP 18888) 实现 ==================== */

/* 从 .nmconnection 文件读取 psk= 字段。文件权限 root:root 600，
 * 设备进程以 root 运行可直接读取。返回 0=成功, -1=失败/无密码 */
static int read_wifi_psk_from_profile(const char *ssid, char *psk_out, size_t psk_sz) {
    char filepath[512];
    FILE *fp;
    char line[256];
    char *p;
    int found = 0;

    if (!ssid || !psk_out || psk_sz == 0)
        return -1;
    psk_out[0] = '\0';

    /* 主路径：/etc/NetworkManager/system-connections/<ssid>.nmconnection */
    snprintf(filepath, sizeof(filepath), "%s%s.nmconnection", NM_CONN_DIR, ssid);
    fp = fopen(filepath, "r");
    if (!fp)
        return -1;

    while (fgets(line, sizeof(line), fp)) {
        trim_line(line);
        /* 匹配 psk= 开头（前面可能有空格） */
        p = strchr(line, 'p');
        while (p) {
            if (strncmp(p, "psk=", 4) == 0) {
                const char *val = p + 4;
                strncpy(psk_out, val, psk_sz - 1);
                psk_out[psk_sz - 1] = '\0';
                found = 1;
                break;
            }
            p = strchr(p + 1, 'p');
        }
        if (found)
            break;
    }
    fclose(fp);
    return found ? 0 : -1;
}

/* 查询已保存 WiFi 列表，返回 cJSON 数组（调用方负责 cJSON_Delete） */
cJSON *app_wifi_list_query(void) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count;
    cJSON *list;
    int active_idx = -1;

    /* 刷新当前连接 SSID，确保 active 判断准确 */
    get_current_wifi();

    count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    if (count < 0)
        count = 0;

    list = cJSON_CreateArray();
    if (!list)
        return NULL;

    for (int i = 0; i < count; i++) {
        cJSON *item = cJSON_CreateObject();
        if (!item)
            continue;
        cJSON_AddStringToObject(item, "ssid", entries[i].ssid);

        /* password：从 .nmconnection 读取；默认 WiFi 用内置密码兜底 */
        char psk[WIFI_PSK_MAX_LENGTH + 1] = {0};
        if (read_wifi_psk_from_profile(entries[i].ssid, psk, sizeof(psk)) == 0)
            cJSON_AddStringToObject(item, "password", psk);
        else if (is_default_wifi_ssid(entries[i].ssid))
            cJSON_AddStringToObject(item, "password", default_password);
        else
            cJSON_AddStringToObject(item, "password", "");

        /* active：wifi_profile_is_in_use 内部已综合判断 */
        int in_use = wifi_profile_is_in_use(entries[i].ssid);
        cJSON_AddBoolToObject(item, "active", in_use ? 1 : 0);
        if (in_use && active_idx < 0)
            active_idx = i;

        /* protected：默认 WiFi (jking) 受保护 */
        cJSON_AddBoolToObject(item, "protected", is_default_wifi_ssid(entries[i].ssid) ? 1 : 0);

        cJSON_AddItemToArray(list, item);
    }

    (void)active_idx;
    return list;
}

/* 切换当前连接到已保存的指定 SSID */
/* 检查指定 SSID 是否已保存（不连接）。
 * 供 agent 在切换前做预校验，便于"先回复 app 再实际切换"。 */
int app_wifi_check_saved(const char *ssid)
{
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count;
    int found = 0;

    if (!ssid || !ssid[0])
        return -1;

    count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    if (count < 0)
        return -1;

    for (int i = 0; i < count; i++) {
        if (strcmp(entries[i].ssid, ssid) == 0) {
            found = 1;
            break;
        }
    }
    return found ? 0 : -1;
}

int app_wifi_switch(const char *ssid) {
    saved_wifi_entry_t entries[MAX_WIFI_ENTRIES];
    int count;
    int found = 0;
    char psk[WIFI_PSK_MAX_LENGTH + 1] = {0};

    if (!ssid || !ssid[0])
        return -1;

    count = collect_saved_wifi_entries(entries, MAX_WIFI_ENTRIES);
    if (count < 0)
        return -1;

    for (int i = 0; i < count; i++) {
        if (strcmp(entries[i].ssid, ssid) == 0) {
            found = 1;
            break;
        }
    }
    if (!found)
        return -1;

    /* 读取已保存密码，无密码则空串连接（开放网络） */
    if (read_wifi_psk_from_profile(ssid, psk, sizeof(psk)) != 0 &&
        is_default_wifi_ssid(ssid))
        snprintf(psk, sizeof(psk), "%s", default_password);

    /* 复用现有连接逻辑：已存在则直接 connect，无密码走无密码分支。
     * 区分返回码：未找到返回 -1，连接失败返回 -2，便于 agent 给准确提示。 */
    if (orange_pi_connect_wifi(ssid, psk[0] ? psk : NULL) == 0)
        return 0;
    my_zlog_error("app_wifi_switch: WiFi 已保存但连接失败 SSID=%s", ssid);
    return -2;
}

/* 删除已保存的指定 SSID（受保护的 jking 不可删） */
int app_wifi_delete(const char *ssid) {
    if (!ssid || !ssid[0])
        return -1;

    /* 受保护检查（与 device_wifi_delete_saved_profile 内部一致，提前返回便于 agent 区分原因） */
    if (is_default_wifi_ssid(ssid))
        return -2;

    /* device_wifi_delete_saved_profile 内部还会检查是否在用，
     * 在用的返回 -3。这里统一映射为 -1 失败，由 agent 组织 message。 */
    int rc = device_wifi_delete_saved_profile(ssid);
    if (rc == 0)
        return 0;
    return -1;
}
