#include "InteractiveFace.h"

#include <QCameraInfo>
#include <QRandomGenerator>
#include <QPainter>
#include <QFont>
#include <QPen>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QAbstractVideoBuffer>
#include <QBuffer>

#ifdef INTERACTIVEFACE_OPENCV
#include <opencv2/objdetect.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#endif

InteractiveFace* InteractiveFace::pInstance = nullptr;

InteractiveFace::InteractiveFace(QObject *parent)
    : QObject(parent)
    , QQuickImageProvider(QQuickImageProvider::Image)
    , m_FrameId(0)
    , m_camera(nullptr)
    , m_probe(nullptr)
{
    m_probe = new QVideoProbe(this);
    connect(m_probe, &QVideoProbe::videoFrameProbed, this, &InteractiveFace::onVideoFrameProbed);

    if (hasCamera()) {
        initCamera();
    }
}

InteractiveFace::~InteractiveFace()
{
    destroyCamera();
}

QString InteractiveFace::getImageUrl()
{
    return QString("image://") +
           QString(INTERACTIVE_FACE_IMAGE_URL) +
           QString("/") +
           QString::number(QRandomGenerator::global()->bounded(10000));
}

QString InteractiveFace::imageUrl()
{
    return getImageUrl();
}

InteractiveFace *InteractiveFace::instance()
{
    if (!pInstance) {
        pInstance = new InteractiveFace(nullptr);
    }
    return pInstance;
}

InteractiveFace *InteractiveFace::create(QQmlEngine *, QJSEngine *)
{
    return instance();
}

void InteractiveFace::setCameraImageGatherCallBack(QJSValue callback)
{
    m_imageGatherCallback = callback;
}

void InteractiveFace::setCameraImageAppearCallBack(QJSValue callback)
{
    m_imageAppearCallback = callback;
}

void InteractiveFace::setCameraImageRemainCallBack(QJSValue callback)
{
    m_imageRemainCallback = callback;
}

void InteractiveFace::setCameraImageCallBack(QJSValue gatherCallback, QJSValue appearCallback, QJSValue remainCallback)
{
    m_imageGatherCallback = gatherCallback;
    m_imageAppearCallback = appearCallback;
    m_imageRemainCallback = remainCallback;
}

void InteractiveFace::setCallBackFaceStatus(QJSValue isAppearCallback)
{
    m_isAppearCallback = isAppearCallback;
}

void InteractiveFace::cameraImagePlay()
{
    if (!hasCamera()) {
        qWarning() << "[InteractiveFace] 无可用摄像头";
        return;
    }
    cameraPlay();
    m_FrameId = 0;
}

void InteractiveFace::cameraImageStop()
{
    if (hasCamera()) {
        cameraStop();
    }
    // 停止采集后立即释放当前帧与检测结果，避免占用内存
    {
        QMutexLocker locker(&m_mutex);
        m_image = QImage();
    }
    {
        QMutexLocker locker(&m_faceMutex);
        m_faceCount = 0;
        m_faceRects.clear();
        m_imageWidth = 0;
        m_imageHeight = 0;
    }
    emit faceDetectionUpdated();
}

QImage InteractiveFace::getImage()
{
    QMutexLocker locker(&m_mutex);
    return m_image.copy();
}

QImage InteractiveFace::requestImage(const QString &, QSize *, const QSize &)
{
    QMutexLocker locker(&m_mutex);
    if (m_image.isNull() || m_image.width() == 0 || m_image.height() == 0) {
        // 返回一个小的占位图像，避免返回空图像导致 QML 报错
        QImage placeholder(1, 1, QImage::Format_RGB32);
        placeholder.fill(Qt::black);
        return placeholder;
    }
    return m_image.copy();
}

void InteractiveFace::onVideoFrameProbed(const QVideoFrame &frame)
{
    if (!frame.isValid()) return;

    QImage image;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    image = frame.image();
#else
    if (frame.map(QAbstractVideoBuffer::ReadOnly)) {
        QImage::Format format = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());
        if (format != QImage::Format_Invalid) {
            image = QImage(frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(), format).copy();
        }
        frame.unmap();
    }
#endif
    if (!image.isNull()) {
        if (++m_FrameId <= 5) return; // 跳过前几帧
        QMutexLocker locker(&m_mutex);
        m_image = image;
        runFaceDetection(m_image);
        if (m_imageGatherCallback.isCallable()) {
            QJSValueList args;
            args << getImageUrl();
            m_imageGatherCallback.call(args);
        }
    }
}

void InteractiveFace::initCamera()
{
    if (m_camera) return;
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    if (cameras.isEmpty()) {
        qWarning() << "[InteractiveFace] 未检测到摄像头";
        return;
    }
    QCameraInfo info = QCameraInfo::defaultCamera();
    if (info.isNull()) info = cameras.first();
    m_camera = new QCamera(info, this);
    if (!m_probe->setSource(m_camera)) {
        qWarning() << "[InteractiveFace] QVideoProbe 绑定摄像头失败";
    }
}

void InteractiveFace::destroyCamera()
{
    cameraStop();
    if (m_camera) {
        m_probe->setSource(static_cast<QMediaObject*>(nullptr));
        delete m_camera;
        m_camera = nullptr;
    }
}

bool InteractiveFace::hasCamera()
{
    return !QCameraInfo::availableCameras().isEmpty();
}

bool InteractiveFace::hasValidImage()
{
    QMutexLocker locker(&m_mutex);
    return !m_image.isNull() && m_image.width() > 0 && m_image.height() > 0;
}

void InteractiveFace::cameraPlay()
{
    if (!m_camera) return;
    if (m_camera->state() != QCamera::ActiveState) {
        m_camera->start();
    }
}

void InteractiveFace::cameraStop()
{
    if (m_camera && m_camera->state() == QCamera::ActiveState) {
        m_camera->stop();
    }
}

int InteractiveFace::faceCount() const
{
    QMutexLocker locker(&m_faceMutex);
    return m_faceCount;
}

QVariantList InteractiveFace::faceRects() const
{
    QMutexLocker locker(&m_faceMutex);
    QVariantList list;
    for (const QRect &r : m_faceRects) {
        QVariantMap m;
        m["x"] = r.x();
        m["y"] = r.y();
        m["width"] = r.width();
        m["height"] = r.height();
        list.append(m);
    }
    return list;
}

int InteractiveFace::imageWidth() const
{
    QMutexLocker locker(&m_faceMutex);
    return m_imageWidth;
}

int InteractiveFace::imageHeight() const
{
    QMutexLocker locker(&m_faceMutex);
    return m_imageHeight;
}

QByteArray InteractiveFace::captureFaceImageForLogin()
{
    QImage img = getImage();
    if (img.isNull() || img.width() < 10 || img.height() < 10)
        return QByteArray();

    int count = faceCount();
    QVariantList rects = faceRects();
    if (count != 1 || rects.isEmpty())
        return QByteArray();

    QVariantMap first = rects.first().toMap();
    int x = first["x"].toInt();
    int y = first["y"].toInt();
    int w = first["width"].toInt();
    int h = first["height"].toInt();
    if (w < 20 || h < 20)
        return QByteArray();

    // 人脸需在画面内且相对完整（不贴边）
    int margin = 15;
    if (x < margin || y < margin || x + w > img.width() - margin || y + h > img.height() - margin)
        return QByteArray();

    // 取正方形区域（以人脸为中心，边长为 face 的 max(w,h) 加适量边距）
    int side = qMax(w, h) + 80;
    int cx = x + w / 2;
    int cy = y + h / 2;
    int x1 = qBound(0, cx - side / 2, qMax(0, img.width() - side));
    int y1 = qBound(0, cy - side / 2, qMax(0, img.height() - side));
    x1 = qMax(0, qMin(x1, img.width() - 1));
    y1 = qMax(0, qMin(y1, img.height() - 1));
    if (x1 + side > img.width()) side = img.width() - x1;
    if (y1 + side > img.height()) side = img.height() - y1;
    if (side < 30) return QByteArray();

    QImage crop = img.copy(x1, y1, side, side);
    if (crop.isNull()) return QByteArray();

    QByteArray ba;
    QBuffer buf(&ba);
    buf.open(QIODevice::WriteOnly);
    if (!crop.save(&buf, "JPEG", 85))
        return QByteArray();
    return ba;
}

bool InteractiveFace::canCaptureFaceForLogin() const
{
    int count = faceCount();
    QVariantList rects = faceRects();
    if (count != 1 || rects.isEmpty())
        return false;

    QVariantMap first = rects.first().toMap();
    int x = first["x"].toInt();
    int y = first["y"].toInt();
    int w = first["width"].toInt();
    int h = first["height"].toInt();
    if (w < 20 || h < 20)
        return false;

    int imgW = imageWidth();
    int imgH = imageHeight();
    if (imgW < 10 || imgH < 10)
        return false;

    int margin = 15;
    if (x < margin || y < margin || x + w > imgW - margin || y + h > imgH - margin)
        return false;

    return true;
}

void InteractiveFace::runFaceDetection(const QImage &image)
{
    if (image.isNull() || image.width() < 20 || image.height() < 20) {
        QMutexLocker locker(&m_faceMutex);
        m_imageWidth = image.width();
        m_imageHeight = image.height();
        m_faceCount = 0;
        m_faceRects.clear();
        return;
    }

#ifdef INTERACTIVEFACE_OPENCV
    cv::Mat gray;
    QImage rgb = image.format() == QImage::Format_RGB32 || image.format() == QImage::Format_ARGB32
                     ? image.copy()
                     : image.convertToFormat(QImage::Format_RGB32);
    if (rgb.bytesPerLine() <= 0) return;
    cv::Mat mat(rgb.height(), rgb.width(), CV_8UC4, rgb.bits(), static_cast<size_t>(rgb.bytesPerLine()));
    // Qt Format_RGB32/ARGB32 在内存中多为 BGRA 顺序，用 BGRA2GRAY
    cv::cvtColor(mat, gray, cv::COLOR_BGRA2GRAY);
    cv::equalizeHist(gray, gray);

    static cv::CascadeClassifier cascade;
    static bool cascadeLoaded = false;
    static bool cascadeTried = false;
    if (!cascadeLoaded && !cascadeTried) {
        cascadeTried = true;
        QStringList paths;
        paths << QCoreApplication::applicationDirPath() + "/haarcascade_frontalface_default.xml"
              << QCoreApplication::applicationDirPath() + "/../haarcascade_frontalface_default.xml"
              << QDir::currentPath() + "/haarcascade_frontalface_default.xml"
              << "/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml"
              << "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml";
        for (const QString &path : paths) {
            if (QFileInfo::exists(path) && cascade.load(path.toStdString())) {
                cascadeLoaded = true;
                qDebug() << "[InteractiveFace] 加载人脸检测模型:" << path;
                break;
            }
        }
        if (!cascadeLoaded)
            qWarning() << "[InteractiveFace] 未找到 haarcascade_frontalface_default.xml，请将文件放到可执行文件同目录或当前目录";
    }

    if (cascadeLoaded && !cascade.empty()) {
        std::vector<cv::Rect> faces;
        cascade.detectMultiScale(gray, faces, 1.1, 4, 0, cv::Size(30, 30));
        QMutexLocker locker(&m_faceMutex);
        m_imageWidth = image.width();
        m_imageHeight = image.height();
        m_faceCount = static_cast<int>(faces.size());
        m_faceRects.clear();
        for (const cv::Rect &r : faces) {
            m_faceRects.append(QRect(r.x, r.y, r.width, r.height));
        }
        locker.unlock();
        emit faceDetectionUpdated();
    } else {
        QMutexLocker locker(&m_faceMutex);
        m_imageWidth = image.width();
        m_imageHeight = image.height();
        m_faceCount = 0;
        m_faceRects.clear();
        locker.unlock();
        emit faceDetectionUpdated();
    }
#else
    QMutexLocker locker(&m_faceMutex);
    m_imageWidth = image.width();
    m_imageHeight = image.height();
    m_faceCount = 0;
    m_faceRects.clear();
    locker.unlock();
    emit faceDetectionUpdated();
#endif
}
