#include "networkInfo.hpp"
#include <iostream>
#include <string.h>     // For memset, strerror
#include <unistd.h>     // For close
#include <sys/ioctl.h>  // For ioctl
#include <sys/socket.h> // For socket
#include <netinet/in.h> // For sockaddr_in
#include <arpa/inet.h>  // For inet_ntoa
#include <net/if.h>     // For ifreq
#include <ifaddrs.h>    // For getifaddrs
#include <iomanip>      // For std::setw, std::setfill
#include <sstream>      // For std::stringstream


std::string NetworkInfo::getipaddress(const std::string& interfaceName) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        std::cerr << "Error creating socket: " << strerror(errno) << std::endl;
        return "";
    }

    struct ifreq ifr;
    // 使用 strncpy 保证安全，避免缓冲区溢出
    strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
    ifr.ifr_name[IFNAMSIZ - 1] = '\0'; // 确保字符串以 null 结尾

    if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
        // 接口可能存在但没有配置IP，这不是一个致命错误
        // std::cerr << "ioctl error for IP on " << interfaceName << ": " << strerror(errno) << std::endl;
        close(sock);
        return "";
    }

    close(sock);

    struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(&ifr.ifr_addr);
    return std::string(inet_ntoa(addr->sin_addr));
}

// 这是新的、不带参数的函数
std::string NetworkInfo::getip() {
    // 1. 获取所有网络接口
    std::vector<std::string> interfaces = getavailableinterfaces();

    // 2. 遍历接口，寻找第一个配置了 IP 的物理接口
    for (const auto& ifaceName : interfaces) {
        // 排除环回接口 "lo"
        if (ifaceName == "lo") {
            continue;
        }

        // 尝试获取该接口的 IP 地址
        std::string ip = getipaddress(ifaceName);

        // 如果成功获取到一个非空的 IP 地址，就立即返回它
        if (!ip.empty()) {
            return ip;
        }
    }

    // 如果遍历完所有接口都没有找到，返回空字符串
    std::cerr << "Error: Could not find a valid IP address on any interface." << std::endl;
    return "";
}



std::string NetworkInfo::getmacaddress(const std::string& interfaceName) {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        std::cerr << "Error creating socket: " << strerror(errno) << std::endl;
        return "";
    }

    struct ifreq ifr;
    strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1);
    ifr.ifr_name[IFNAMSIZ - 1] = '\0';

    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
        std::cerr << "ioctl error for MAC on " << interfaceName << ": " << strerror(errno) << std::endl;
        close(sock);
        return "";
    }

    close(sock);

    unsigned char* mac_addr = reinterpret_cast<unsigned char*>(ifr.ifr_hwaddr.sa_data);
    
    // 格式化 MAC 地址
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (int i = 0; i < 6; ++i) {
        ss << std::setw(2) << static_cast<int>(mac_addr[i]);
        if (i < 5) {
            ss << ":";
        }
    }
    
    // 转换为大写
    std::string result = ss.str();
    for (char &c : result) {
        c = toupper(c);
    }

    return result;
}

// 这是新的、不带参数的函数
std::string NetworkInfo::getmac() {
    // 1. 获取所有网络接口
    std::vector<std::string> interfaces = getavailableinterfaces();
    
    // 2. 遍历接口，寻找第一个有效的物理接口
    for (const auto& ifaceName : interfaces) {
        // 排除环回接口 "lo"
        if (ifaceName == "lo") {
            continue;
        }

        // 尝试获取该接口的 MAC 地址
        std::string mac = getmacaddress(ifaceName);

        // 如果成功获取到一个非空的 MAC 地址，就立即返回它
        if (!mac.empty()) {
            return mac;
        }
    }
    
    // 如果遍历完所有接口都没有找到，返回空字符串
    std::cerr << "Error: Could not find a valid MAC address on any interface." << std::endl;
    return "";
}


std::vector<std::string> NetworkInfo::getavailableinterfaces() {
    std::vector<std::string> interfaces;
    struct ifaddrs *ifaddr, *ifa;

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        return interfaces;
    }

    // 遍历链表
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL) {
            continue;
        }

        // 检查是否是新的接口名
        bool found = false;
        for (const auto& name : interfaces) {
            if (name == ifa->ifa_name) {
                found = true;
                break;
            }
        }
        if (!found) {
            interfaces.push_back(ifa->ifa_name);
        }
    }

    freeifaddrs(ifaddr);
    return interfaces;
}