#include "HttpFaceLogin.h"
#include "../usr/config.h"
#include "../interactive/InteractiveData.h"
#include "../interactive/InteractiveHttp.h"
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QEventLoop>
#include <QFile>
#include <QHttpPart>
#include <QHttpMultiPart>
#include <QImage>
#include <QMetaObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRandomGenerator>
#include <QTimer>
#include <QUrl>
#include <QJsonDocument>
#include <QJsonObject>

HttpFaceLogin::HttpFaceLogin(QObject *parent)
    : QThread(parent)
{
}

void HttpFaceLogin::setFaceImageData(const QByteArray &data)
{
    m_faceImageData = data;
}

void HttpFaceLogin::pushFaceImage(const QByteArray &data)
{
    if (data.isEmpty()) return;
    QMutexLocker lock(&m_queueMutex);
    m_faceImageQueue.append(data);
    while (m_faceImageQueue.size() > FACE_QUEUE_MAX_SIZE)
        m_faceImageQueue.removeFirst();
    qDebug().noquote() << "[HttpFaceLogin] 人脸图入队, 大小:" << data.size() << "字节 队列长度:" << m_faceImageQueue.size();
}

QByteArray HttpFaceLogin::takeRandomFaceImage()
{
    QMutexLocker lock(&m_queueMutex);
    if (m_faceImageQueue.isEmpty()) return QByteArray();
    const int n = m_faceImageQueue.size();
    int idx = (n <= 1) ? 0 : QRandomGenerator::global()->bounded(n);
    QByteArray taken = m_faceImageQueue.takeAt(idx);
    qDebug().noquote() << "[HttpFaceLogin] 人脸图出队(随机取1张), 剩余队列:" << m_faceImageQueue.size();
    return taken;
}

void HttpFaceLogin::clearFaceQueue()
{
    QMutexLocker lock(&m_queueMutex);
    m_faceImageQueue.clear();
    m_faceImageData.clear();
}

void HttpFaceLogin::run()
{
    qDebug() << "[HttpFaceLogin] run() 开始，准备请求人脸登录 API";
    // 在工作线程内从队列取图，避免与主线程 setFaceImageData 的竞争导致读到空数据
    QByteArray img = takeRandomFaceImage();
    if (img.isEmpty()) {
        qDebug() << "[HttpFaceLogin] 队列无图，跳过本次请求";
        return;
    }
    m_faceImageData = img;
    httpRequestFaceLogin();
    qDebug() << "[HttpFaceLogin] run() 结束";
}

static const int FACE_LOGIN_TIMEOUT_MS = 15000;

void HttpFaceLogin::httpRequestFaceLogin()
{
    if (m_faceImageData.isEmpty()) {
        qWarning() << "[HttpFaceLogin] 人脸图数据为空，跳过请求";
        return;
    }
    config *cfg = Config();
    if (!cfg) return;
    QString host = cfg->httpHost;  // 与刷卡登录等接口统一使用框架 httpHost
    QString path = cfg->loginByFace_url;
    QString token;
    if (InteractiveData *data = GetInteractiveData()) token = data->m_token;

    // 可选：调试用，将人脸头像保存到 face_capture/
    QDir dir;
    if (!dir.exists("face_capture")) dir.mkpath("face_capture");
    QString fileName = QString("face_capture/face_%1.png").arg(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"));
    QString absPath = dir.absoluteFilePath(fileName);
    QImage img;
    if (img.loadFromData(m_faceImageData)) {
        if (!img.save(absPath, "PNG")) {
            QFile f(absPath);
            if (f.open(QIODevice::WriteOnly)) { f.write(m_faceImageData); f.close(); }
        }
    } else {
        QFile f(absPath);
        if (f.open(QIODevice::WriteOnly)) { f.write(m_faceImageData); f.close(); }
    }

    // 人脸登录：本模块自建 QNAM 发 multipart POST，不占用 HttpClient
    QString fullUrl = QString("http://%1%2").arg(host).arg(path);
    qDebug().noquote() << "[HttpFaceLogin] 请求人脸登录 API:" << fullUrl
                       << " tenant-id=" << cfg->tenant_id
                       << " Authorization=" << (token.isEmpty() ? "(空)" : "(已设置)");
    QUrl url(fullUrl);
    bool isPng = m_faceImageData.size() >= 8 && m_faceImageData.startsWith("\x89PNG\r\n\x1a\n");
    QString partContentType = isPng ? "image/png" : "image/jpeg";
    QString partFileName = isPng ? "img.png" : "face.jpg";

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, partContentType.toUtf8());
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                       QString("form-data; name=\"file\"; filename=\"%1\"").arg(partFileName).toUtf8());
    filePart.setBody(m_faceImageData);
    multiPart->append(filePart);

    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader,
                      "multipart/form-data; boundary=" + multiPart->boundary());
    QString authValue = token.trimmed();
    if (!authValue.isEmpty() && !authValue.startsWith("Bearer ", Qt::CaseInsensitive))
        authValue = "Bearer " + authValue;
    request.setRawHeader("Authorization", authValue.toUtf8());
    QString tenantId = cfg->tenant_id.trimmed();
    if (!tenantId.isEmpty())
        request.setRawHeader("tenant-id", tenantId.toUtf8());
    else
        qWarning() << "[HttpFaceLogin] tenant_id 为空，未设置 tenant-id 请求头，可能导致 403 您无权访问该租户的数据";

    QNetworkAccessManager nam;
    QNetworkReply *reply = nam.post(request, multiPart);
    multiPart->setParent(reply);

    QEventLoop loop;
    QTimer::singleShot(FACE_LOGIN_TIMEOUT_MS, &loop, &QEventLoop::quit);
    connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();

    QByteArray responseData;
    if (reply->isFinished()) {
        int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        if (reply->error() == QNetworkReply::NoError) {
            responseData = reply->readAll();
        } else {
            QString err = reply->errorString();
            err.replace("\\", "\\\\").replace("\"", "\\\"");
            responseData = QString("{\"code\":%1,\"result\":\"%2\"}").arg(statusCode).arg(err).toUtf8();
        }
    } else {
        reply->abort();
        responseData = QByteArray("{\"code\":408,\"result\":\"Request timeout\"}");
    }
    reply->deleteLater();

    // 回到主线程解析并通知登录结果
    QMetaObject::invokeMethod(this, "slotHttpResponseFaceLogin", Qt::QueuedConnection, Q_ARG(QByteArray, responseData));
}

// 可能被多次调用（多个人脸请求在途），QML 侧用 faceLoginSuccessPending 只处理第一次成功
void HttpFaceLogin::slotHttpResponseFaceLogin(QByteArray data)
{
    QJsonParseError parseErr;
    QJsonDocument doc = QJsonDocument::fromJson(data, &parseErr);
    if (parseErr.error != QJsonParseError::NoError || !doc.isObject()) {
        qDebug() << "[HttpFaceLogin] 响应解析失败或非 JSON 对象";
        emit signalFaceLoginError(QStringLiteral("响应解析失败"));
        return;
    }
    QJsonObject obj = doc.object();
    int code = obj.value("code").toInt(-1);
    // 兼容 code 0 或 200 表示成功
    if (code != 0 && code != 200) {
        QString msg;
        if (code == 408)
            msg = QStringLiteral("处理超时，请稍后重试。");
        else {
            msg = obj.value("msg").toString();
            if (msg.isEmpty()) msg = obj.value("result").toString();
            if (msg.isEmpty()) msg = QString::fromUtf8(data).left(200);
        }
        qDebug().noquote() << "[HttpFaceLogin] API 返回非200 code:" << code << "msg:" << msg;
        emit signalFaceLoginError(msg);
        return;
    }

    QString nickName;
    QString token;
    QJsonValue dataVal = obj.value("data");
    if (dataVal.isObject()) {
        QJsonObject dataObj = dataVal.toObject();
        token = dataObj.value("accessToken").toString();
        if (token.isEmpty()) token = dataObj.value("token").toString();
        nickName = dataObj.value("nickname").toString();
        if (nickName.isEmpty()) nickName = dataObj.value("nickName").toString();
    }
    if (nickName.isEmpty()) nickName = obj.value("nickName").toString();
    if (nickName.isEmpty()) nickName = QStringLiteral("用户");
    if (token.isEmpty()) token = obj.value("token").toString();
    if (!token.isEmpty()) {
        if (InteractiveData *d = GetInteractiveData()) d->m_token = token;
        InteractiveHttp::strToken = token;
    }
    if (config *cfg = Config()) cfg->username = nickName;
    qDebug().noquote() << "[HttpFaceLogin] 人脸登录成功, nickName:" << nickName;
    // 识别成功即清空队列与缓存，释放内存，不依赖 QML 再调 clearFaceQueue
    clearFaceQueue();
    emit signalFaceLoginSuccess(nickName);
}
