#include "AdbUtils.h"
#include <QProcess>
#include <qDebug>
#include <QString>

AdbUtils::AdbUtils(QObject *parent) : QObject(parent) {
}

// adb shell dumpsys package ru.rshb.dbo | grep permission
// TODO доделать обработку пермишинов
// adb shell pm revoke ru.rshb.dbo android.permission.WRITE_CONTACTS; adb shell pm revoke ru.rshb.dbo android.permission.READ_CONTACTS; adb shell pm revoke ru.rshb.dbo android.permission.ACCESS_COARSE_LOCATION; adb shell pm revoke ru.rshb.dbo android.permission.ACCESS_FINE_LOCATION

// adb shell cmd appops set ru.rshb.dbo POST_NOTIFICATION ignore
/**
 * Возвращает список найденных устройств в виде пар (ID устройства и Статус)
 * @return [(id, status), ...]
 */
QList<QPair<QString, QString> > AdbUtils::getListDevices() {
    QProcess process;
    process.start("adb", {"devices"});
    process.waitForFinished();

    const QString output = process.readAllStandardOutput();
    QList<QPair<QString, QString> > devices;

    const QStringList lines = output.split('\n');
    for (int i = 1; i < lines.size(); ++i) {
        QString line = lines.at(i).trimmed();

        if (line.isEmpty()) {
            continue;
        }
        /**
        * device — устройство готово к использованию.
        * offline — устройство подключено, но не может быть использовано.
        * unauthorized — устройство не авторизовано для работы с ADB (нужно подтвердить запрос на подключение на самом устройстве).
        * recovery — устройство в режиме восстановления.
        */
        if (QStringList parts = line.split('\t'); parts.size() == 2) {
            const QString &id = parts.at(0);
            const QString &status = parts.at(1);
            devices.append(qMakePair(id, status));
        }
    }
    return devices;
}

QString AdbUtils::tryToGetRunningAppPid(const QString &deviceId, const QString &packageName) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "pidof", packageName
                  });
    process.waitForFinished();
    QString pid = process.readAllStandardOutput();
    return pid.replace("\n", "");
}

bool AdbUtils::tryToStartApplication(const QString &deviceId, const QString &packageName) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "monkey",
                      "-p", packageName,
                      "-c", "android.intent.category.LAUNCHER",
                      "1"
                  });
    process.waitForFinished();
    const QString output = process.readAllStandardOutput();

    // Если процесс запустился, там будет такая строка.
    // Если нет, то: "** No activities found to run, monkey aborted."
    if (output.contains("Events injected: 1")) {
        return true;
    }

    // Тут надо в логи писать, почему не стартует
    qDebug() << "Start app output:" << output;
    return false;
}

bool AdbUtils::tryToKillApplication(const QString &deviceId, const QString &packageName) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "am",
                      "force-stop", packageName
                  });
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

// idx - временный лог
// adb -s 6edc4a47 shell 'uiautomator dump /sdcard/uidump.xml' && adb -s 6edc4a47 pull /sdcard/uidump.xml step_1.xml &&  adb -s 6edc4a47 shell 'rm /sdcard/uidump.xml'
QString AdbUtils::getScreenDumpAsXml(const QString &deviceId, const int idx) {
    // TODO убрать логирование в xml файл
    // "adb -s %1 pull /sdcard/uidump.xml step_%2.xml && "
    QProcess process;
    QString xml = QString(
        "adb -s %1 shell 'uiautomator dump /sdcard/uidump.xml' && "

        "adb -s %1 shell 'cat /sdcard/uidump.xml' && "
        "adb -s %1 shell 'rm /sdcard/uidump.xml'"
    // ).arg(deviceId, QString::number(idx));
    ).arg(deviceId);
    process.start("sh", {"-c", xml});
    process.waitForFinished();

    if (false) {
        // TODO делаем скрин, убрать потом
        // adb -s 6edc4a47 shell 'screencap -p /sdcard/screen.png' && adb -s 6edc4a47 pull /sdcard/screen.png screen_step_1.png && adb -s 6edc4a47 shell 'rm /sdcard/screen.png'
        QProcess processScreenshot;
        QString screenshot = QString(
            "adb -s %1 shell 'screencap -p /sdcard/screen.png' && "
            "adb -s %1 pull /sdcard/screen.png screen_step_%2.png && "
            "adb -s %1 shell 'rm /sdcard/screen.png'"
        ).arg(deviceId, QString::number(idx));
        processScreenshot.start("sh", {"-c", screenshot});
        processScreenshot.waitForFinished();
    }

    // чтобы убедиться, что мы прочитали без ошибок
    if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
        return {};
    }

    QByteArray xmlBytes = process.readAllStandardOutput();
    // UI hierchary dumped to: /sdcard/uidump.xml\n
    if (const int startIndex = xmlBytes.indexOf("<?xml"); startIndex != -1) {
        xmlBytes = xmlBytes.mid(startIndex); // Обрезаем всё до "<?xml"
    }
    return QString::fromUtf8(xmlBytes);
}

bool AdbUtils::takeScreenshot(const QString &deviceId, const QString &name) {
    QProcess process;
    QString screenshot = QString(
        "adb -s %1 shell 'screencap -p /sdcard/screen.png' && "
        "adb -s %1 pull /sdcard/screen.png screen_%2.png && "
        "adb -s %1 shell 'rm /sdcard/screen.png'"
    ).arg(deviceId, name);
    process.start("sh", {"-c", screenshot});
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::makeTap(const QString &deviceId, const int x, const int y) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "input",
                      "tap", QString::number(x), QString::number(y)
                  });
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) {
    QProcess process;
    QString command = QString(
        "adb -s %1 shell ime enable com.android.adbkeyboard/.AdbIME "
        "&& adb -s %1 shell ime set com.android.adbkeyboard/.AdbIME"
    ).arg(deviceId);
    process.start(command);
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::inputAdbIMEText(const QString &deviceId, const QString &text) {
    QProcess process;
    QString command = QString(
        "adb -s %1 shell am broadcast -a ADB_INPUT_TEXT --es msg '%2'"
    ).arg(deviceId, text);
    process.start(command);
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::disableAdbIMEKeyboard(const QString &deviceId) {
    QProcess process;
    QString command = QString(
        "adb -s %1 shell ime disable com.android.adbkeyboard/.AdbIME"
    ).arg(deviceId);
    process.start(command);
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::makeSwipe(const QString &deviceId, const int x1, const int y1, const int x2, const int y2) {
    QProcess process;
    process.start(
        "adb",
        {
            "-s", deviceId,
            "shell", "input",
            "swipe", QString("%1 %2 %3 %4").arg(x1).arg(y1).arg(x2).arg(y2)
        }
    );
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::inputText(const QString &deviceId, const QString &text) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "input",
                      "text", text
                  });
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}

bool AdbUtils::goBack(const QString &deviceId) {
    QProcess process;
    process.start("adb", {
                      "-s", deviceId,
                      "shell", "input",
                      "keyevent", "4"
                  });
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}
