#ifndef VIDESDATA_H
#define VIDESDATA_H

#include "XNetSDKDefine.h"
#include<QString>
#include <QProcess>
#include <QDate>
#include <QProcess>
#include <QRegularExpression>
#include <QFile>
#include <QTextStream>
#include <QByteArray> 
#include <QNetworkInterface>
#include <iostream>
#include <cstdio>
#include <string>
#include <sstream>
#include <list>
#include "Common.h"
namespace vides_data{
constexpr const char *HEADER_TYPE_KAY="Content-Type";
constexpr const char *HEADER_TYPE_VALUE="application/json";
constexpr const char *PROFLIE_TEST= "test";
constexpr const char *PROFLIE_DEV= "dev";

struct response
{
    int code;
    void* data;
    QString msg;
    response() {}
};

struct requestCameraInfo{
    
    QString ip_addr;
    QString firmware_version;
    QString sSn;
    QString mac;
    requestCameraInfo() {}
};

struct requestDeviceStatus
{
    QString sSn;
    int8_t type;
    int8_t status;
    QString ip_addr;
    QString firmware_version;
    QString mac;
    std::list<requestCameraInfo>camera_info_list;
    requestDeviceStatus() {}
};
struct responseStsCredentials{
    QString access_key_id;
    QString access_key_secret;
    QString bucket;
    QString endpoint;
    QString expiration;
    QString security_token;
};
struct responseGb28181 {
    QString sip_ip;
    int sip_port;
    QString serial;
    QString realm;
    QString username;
    QString password;
    int register_validity;
    int heartbeat_interval;
    QString device_id;
    QString channel_id;
    int  sUdpPort;
};
struct responseArea {
    float bottom_right_corner_x;
    float bottom_right_corner_y;
    float bottom_left_corner_x;
    float bottom_left_corner_y;
    
    float top_left_corner_x;
    float top_left_corner_y;
    float top_right_corner_x;
    float top_right_corner_y;
};
struct responseDeviceStatus
{
    QString sSn;
    int8_t type;
    int8_t merchant_id;
    bool is_reboot;
    std::list<responseArea>areas;
    responseDeviceStatus() : is_reboot(false) {}
};
struct responseDeviceData{
    int algorithm ;
    std::list<responseDeviceStatus> list;
    responseStsCredentials sts_credentials;
};

struct localDeviceStatus
{
    QString sSn;
    int8_t type;
    int8_t merchant_id;
    SXSDK_IPAddress HostIP;
    int HttpPort;
    int TCPPort;
    int ChannelNum;
    QString UserName;
    QString password;
    QString mac;
    localDeviceStatus() {}
};
struct localDevice
{
    QString sSn;
    QString reachableIp;
    bool isMask;
    int nDevPort;
    int TCPPort;
    int ChannelNum;
    QString UserName;
    QString password;
    localDevice() {}
};

struct requestFaceReconition
{
    QString id;
    QByteArray  img;
    QString sn;
    qint64 time;
    responseArea area;
    requestFaceReconition() {}
};

struct faceRecognitionResult
{
    QString id;
    uint32_t x;
    uint32_t y;
    uint32_t width;
    uint32_t height;
    faceRecognitionResult() {}
};
struct responseFaceReconition
{
    QString id;
    QString  img;
    responseFaceReconition() {}
};
struct ParkingArea
{
    float topLeftCornerX;
    float topLeftCornerY;
    float bottomLeftCornerX;
    float bottomLeftCornerY;
    float bottomRightCornerX;
    float bottomRightCornerY;
    float topRightCornerX;
    float topRightCornerY;
    ParkingArea() {}
};
struct LicensePlate
{
    ParkingArea areaLocation;
    QString new_plate;
    QString new_color;
    QByteArray  img;
    qint64 time;
    ParkingArea recognition;//识别区域
    float text_confidence;
    LicensePlate() {}
};

struct requestLicensePlate
{  
    QString sn;
    std::list<LicensePlate> plates;
    requestLicensePlate() {}
};

struct cameraParameters
{
    QString sDevId;
    int nDevPort;
    QString sUserName;
    QString sPassword;
    int channel;
    QString httpUrl;
    QString sSn;
    QString rtspUrl;
    QString rtmpUrl;
    QString mac;
    cameraParameters() {}
};
struct NetWorkNetCommon {
    char* GateWay;        // 网关IP
    char* HostIP;         // 主机IP
    char* HostName;       // 主机名
    int HttpPort;           // HTTP服务端口
    char* MAC;            // MAC地址
    int MaxBps;             // 限定码流值
    char* MonMode;        // 监视协议 {"TCP","UDP","MCAST",…}
    int SSLPort;            // SSL侦听端口
    char* Submask;        // 子网掩码
    int TCPMaxConn;         // 最大连接数
    int TCPPort;            // TCP侦听端口
    char* TransferPlan;   // 传输策略"AutoAdapt":自适应, "Quality":质量优先, "Fluency":流量优先，"Transmission":网传优先
    int UDPPort;            // UDP侦听端口
    bool UseHSDownLoad;     // 是否启用高速录像下载
};


struct responseRecognitionData
{
    int id;
    qint64 inTime;
    qint64 outTime;
    int recognitionType;
    QString sn;
};

struct MainFormat {
    bool AudioEnable;
    int BitRate;
    QString BitRateControl;
    QString Compression;
    int FPS;
    int GOP;
    int Quality;
    QString Resolution;
    int VirtualGOP;
    bool VideoEnable;
    quint64 updateAt;
};

struct ExtraFormat {
    bool AudioEnable;
    int BitRate;
    QString BitRateControl;
    QString Compression;
    int FPS;
    int GOP;
    int Quality;
    QString Resolution;
    int VirtualGOP;
    bool VideoEnable;
    quint64 updateAt;
    
};

struct TimerSettings {
    int deleteLogFileTimer;
    int devicePermissionSynTimer;
    quint64 updateAt;
};
struct Camera {
    int devSnapSynTimer;
    int imageSave;
    QString password;
    QString username;
    float heightReference;
    quint64 updateAt;
};
struct FaceConfig {
    bool isOn;
    int faceNumbers;
    float confidence;
    int faceLen;
    quint64 updateAt;
};

struct LicensePlateConfig {
    bool isOn;
    float carConfidenceMax;
    float carConfidenceMin;
    int licensePlateLen;
    quint64 updateAt;
    int maxNum;                                    ///< 识别最大数量
    bool useHalf;                                  ///< 是否使用半精度推理模式
    float boxConfThreshold;                        ///< 检测框阈值
    float nmsThreshold;                             ///< 非极大值抑制阈值
    float recConfidenceThreshold;                   ///< 识别置信度阈值
    bool isHigh;
};


struct UniformConfig {
    bool isOn;
    int uniformColor;
    int humanDetectionLen;
    float carShapeConfidence;
    quint64 updateAt;
    
};
struct HumanConfig{
    bool isOn;
    uint64 faceFrequency;
    quint64 updateAt;
};

struct MqttConfig {
    QString address;
    QString clientId;
    int qos;
    quint64 timeout;
    QString topic;
    QString username;
    QString password;
    quint64 updateAt;
};

struct responseConfig {
    MainFormat mainFormat;
    ExtraFormat extraFormat;
    TimerSettings timerSettings;
    FaceConfig faceConfig;
    LicensePlateConfig licensePlateConfig;
    UniformConfig uniformConfig;
    Camera camera;
    MqttConfig mqttConfig;
    
    HumanConfig humanConfig;
};

struct responseMqttData{
    uint8_t msg_type;
    QString sn;
    QString uniq;
    QString msg_body;
};

struct requestMqttData{
    QString msg;
    int  code;
    QString uniq;
};
struct DetectionParams {
    int newHumanDetectionLen;
    int newLicensePlateLen;
    int newFaceLen;
    QString modelPaths;
    float humanCarShapeConfidence;
    int uniformColor;
    std::map<QString, QString> faceMaps;
    int numberFaces;
    float faceConfidence;
    __uint8_t algorithmPermissions;
    bool isHigh;
    int maxNum;                                ///< 识别最大数量
    bool useHalf;                              ///< 是否使用半精度推理模式
    float boxConfThreshold;                    ///< 检测框阈值
    float nmsThreshold;                       ///< 非极大值抑制阈值
    float recConfidenceThreshold;             ///< 识别置信度阈值
};


inline bool isVirtualMachine()
{
    QString dmiPath;
    
#ifdef Q_OS_WIN
    dmiPath = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System";
#else
    dmiPath = "/sys/devices/virtual/dmi/id/";
#endif
    
    QFile file(dmiPath);
    return file.exists();
}
inline QString getDefaultGateway() {
    QProcess process;
    QString gateway;
    // 根据操作系统的不同选择不同的命令
#ifdef Q_OS_WIN
    QString command = "ipconfig";
    QStringList arguments;
    arguments << "/all";
#elif defined(Q_OS_LINUX)
    QString command = "ip";
    QStringList arguments;
    arguments << "route" << "show" << "default";
#elif defined(Q_OS_MAC)
    QString command = "netstat";
    QStringList arguments;
    arguments << "-nr";
#endif
    
    process.start(command, arguments);

    // 等待进程结束
    process.waitForFinished();
    
    // 读取并处理输出
    QString output(process.readAllStandardOutput());
    
#ifdef Q_OS_WIN
    // 使用正则表达式来查找默认网关
    QRegExp rx("Default Gateway[ .]*: (.+?)(\r\n|\n)");
    if (rx.indexIn(output) != -1) {
        gateway = rx.cap(1).trimmed();
    }
#elif defined(Q_OS_LINUX) || defined(Q_OS_MAC)
    // 对于Linux和Mac，分行并查找包含default字样的行
    QStringList lines = output.split('\n');
    QRegularExpression rx("^default via (\\S+)");
    foreach (const QString &line, lines) {
        QRegularExpressionMatch match = rx.match(line);
        if (match.hasMatch()) {
            gateway = match.captured(1);
            break;
        }
    }
    
#endif
    return gateway;
}

inline void convertQStringToSXSDK_IPAddress(const QString& ipString, SXSDK_IPAddress& hostIP) {
    QHostAddress address(ipString);
    quint32 ip = address.toIPv4Address();

    hostIP.c[0] = (ip >> 24) & 0xFF;
    hostIP.c[1] = (ip >> 16) & 0xFF;
    hostIP.c[2] = (ip >> 8) & 0xFF;
    hostIP.c[3] = ip & 0xFF;
}
inline bool isInSameSubnet(const QString &ip1, const QString &ip2, const QString &mask)
{
    QHostAddress address1(ip1);
    QHostAddress address2(ip2);
    QHostAddress subnetMask(mask);

    // 将IP地址和子网掩码从QHostAddress转换成quint32形式
    quint32 addr1 = address1.toIPv4Address();
    quint32 addr2 = address2.toIPv4Address();
    quint32 maskAddr = subnetMask.toIPv4Address();

    // 进行AND操作
    quint32 result1 = addr1 & maskAddr;
    quint32 result2 = addr2 & maskAddr;

    // 比较结果
    return result1 == result2;
}

inline QString getHostMacAddress()
{
    QList<QNetworkInterface> nets = QNetworkInterface::allInterfaces();// 获取所有网络接口列表
    int nCnt = nets.count();
    QString strMacAddr = "";
    for(int i = 0; i < nCnt; i ++)
    {
        // 如果此网络接口被激活并且正在运行并且不是回环地址，则就是我们需要找的Mac地址
        if(nets[i].flags().testFlag(QNetworkInterface::IsUp) && nets[i].flags().testFlag(QNetworkInterface::IsRunning) && !nets[i].flags().testFlag(QNetworkInterface::IsLoopBack))
        {
            strMacAddr = nets[i].hardwareAddress();
            break;
        }
    }
    return strMacAddr.toLower();
}

// 获取子网掩码
inline bool GetSubnetMask(QString &subnetMask) {
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    foreach (QNetworkInterface interface, interfaces) {
        if (interface.flags().testFlag(QNetworkInterface::IsUp) &&
                interface.flags().testFlag(QNetworkInterface::IsRunning) &&
                !interface.flags().testFlag(QNetworkInterface::IsLoopBack)) {

            QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
            foreach (QNetworkAddressEntry entry, addressEntries) {
                if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                    subnetMask = entry.netmask().toString();
                    return true; // 成功获取子网掩码
                }
            }
        }
    }

    // 如果没有找到合适的接口或子网掩码
    subnetMask = "Unknown";
    return false;
}
inline bool pingAddress(const QString &address) {
    QProcess cmd;

#ifdef Q_OS_WIN
    // Windows 指令 "ping IP -n 1 -w 超时(ms)"
    QStringList arguments;
    arguments << "-c" << "ping " + address + " -n 1 -w 1000";
#else
    // Linux 指令 "ping -c 1 IP"
    QStringList arguments;
    arguments << "-c" << "1" << address;
#endif

    // 启动进程
    cmd.start("/bin/ping", arguments);

    // 等待进程准备好读取
    if (!cmd.waitForStarted()) {
        qWarning() << "无法启动的‘ping’进程" << address;
        qWarning() << "命令: " << arguments.join(" ");
        return false;
    }

    // 等待进程完成
    if (!cmd.waitForFinished(3000)) { // 增加超时时间
        cmd.kill();
        qWarning() << "Ping process timed out for" << address;
        return false;
    }

    // 读取输出
    QByteArray output = cmd.readAllStandardOutput();
    QByteArray errorOutput = cmd.readAllStandardError();
    int exitCode = cmd.exitCode();

    qInfo() << "Ping Output for" << address << ":" << QString::fromUtf8(output);
    qInfo() << "Ping Error Output for" << address << ":" << QString::fromUtf8(errorOutput);
    qInfo() << "Ping Exit Code for" << address << ":" << exitCode;

    // 判断 Ping 是否成功
    if (exitCode == 0) {
        qInfo() << address << "ping通";
        return true;
    } else {
        qInfo() << address << "ping不通";
        return false;
    }
}

inline QString findReachableIp() {
    Common & instace= Common::getInstance();

    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    for (const QHostAddress &address : ipAddressesList) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol && !address.isLoopback()) {
            QString ipAddress = address.toString();
            QString currentSubnet = ipAddress.left(ipAddress.lastIndexOf('.') + 1); // 返回子网部分

            for (int i = 254; i >= 1; --i) { // 从 254 开始递减
                QString ip = currentSubnet + QString::number(i);
                qInfo() << "Found findReachableIp IP:" << ip;
                if (!instace.pingAddress(ip)) {
                    qInfo() << "ping 不通的ip:" << ip;
                    return ip;
                }
            }
        }
    }
    return QString(); // 如果没有找到可用的 IP 地址，则返回空字符串
}

inline int GetCpuIdByAsm_arm(char* cpu_id)
{
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if(nullptr == fp)
    {
        qInfo()<<"failed to open cpuinfo";
        return -1;
    }
    
    char cpuSerial[100] = {0};
    
    while(!feof(fp))
    {
        memset(cpuSerial, 0, sizeof(cpuSerial));
        fgets(cpuSerial, sizeof(cpuSerial) - 1, fp); // leave out \n
        
        char* pch = strstr(cpuSerial,"Serial");
        if (pch)
        {
            char* pch2 = strchr(cpuSerial, ':');
            if (pch2)
            {
                memmove(cpu_id, pch2 + 2, strlen(cpuSerial));
                
                break;
            }
            else
            {
                fclose(fp);
                return -1;
            }
        }
    }
    fclose(fp);
    
    return 0;
}

inline QString getCpuSerialNumber() {
    QFile file("/proc/cpuinfo");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qInfo() << "无法打开 /proc/cpuinfo 文件";
        return QString();
    }
    QTextStream in(&file);
    QString line;
    while (!in.atEnd()) {
        line = in.readLine();
        if (line.startsWith("Serial")) {
            QStringList parts = line.split(":");
            if (parts.size() > 1) {
                QString serial = parts.at(1).trimmed();
                return serial;
            }
        }
    }
    return QString();
}
}


#endif // VIDESDATA_H
