#include "HomeScreenScript.h"

#include <QThread>
#include <QDebug>
#include <QProcess>
#include <QRandomGenerator>

#include "ScreenXmlParser.h"
#include "adb/AdbUtils.h"


HomeScreenScript::HomeScreenScript(const int transactionId, QObject *parent)
    : QObject(parent), transactionId(transactionId) {
}

HomeScreenScript::~HomeScreenScript() = default;

bool HomeScreenScript::goToHomeScreen(
    const QString &deviceId,
    const QString &packageName,
    const QString &pinCode,
    const int width,
    const int height
) {
    // Запустить устройство
    if (const QString pid = AdbUtils::tryToGetRunningAppPid(deviceId, packageName); !pid.isEmpty()) {
        qDebug() << "Process already running, pid: " << pid;
        AdbUtils::getScreenDumpAsXml(deviceId, 1000);
        AdbUtils::tryToKillApplication(deviceId, packageName);
    }
    if (!AdbUtils::tryToStartApplication(deviceId, packageName)) {
        qWarning() << "Process has not started";
        return false;
    }

    xmlScreenParser.parseAndSaveXml(
        AdbUtils::getScreenDumpAsXml(deviceId, 0)
    );

    // Даем минимальное время на запуск
    QThread::msleep(4500);
    int counter = 0;
    int restarted = 0;
    int totalCounter = 0;
    bool findAndInputPincode = false;
    while (true) {
        counter++;
        totalCounter++;

        // 3 раза уже перезапускали приложение, завершаем попытки
        if (restarted > 2) {
            return false;
        }

        // Если более 30 секунд мы пытаемся перейти на домашнюю, перезапускаем
        if (counter > 30) {
            AdbUtils::tryToKillApplication(deviceId, packageName);
            QThread::msleep(4500);
            ++restarted;
            counter = 0;
        }

        const QString xml = AdbUtils::getScreenDumpAsXml(deviceId, totalCounter + 1);
        xmlScreenParser.parseAndSaveXml(xml);
        qDebug() << "Created xml+screenshot, idx: " << (totalCounter + 1);

        if (xmlScreenParser.isHomeScreen()) {
            qDebug() << "isHomeScreen!!!!!!!";
            return true;
        }

        // Проверяем на банеры после пин-кодом
        Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(width, height);
        if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) {
            qDebug() << "--- tryToFindBannerOrDialog";
            AdbUtils::makeTap(deviceId, closeBannerOrDialogNode.x(), closeBannerOrDialogNode.y());
            QThread::msleep(1000);
            continue;
        }

        // Проверяем на банеры перед пин-кодом
        Node closeBannerNode = xmlScreenParser.tryToFindSecurityBanner();
        if (!closeBannerNode.isEmpty()) {
            qDebug() << "--- tryToFindSecurityBanner";
            AdbUtils::makeTap(deviceId, closeBannerNode.x(), closeBannerNode.y());
            QThread::msleep(1000);
            continue;
        }

        // Проверяем, что это экран ввода пин-кода
        if (!findAndInputPincode) {
            if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите ПИН");
                pincode.size() == 4) {
                qDebug() << "--- tryToFindPinCode";
                // делаем 4 тапа и ждем секунду и продолжаем
                for (const Node &node: pincode) {
                    AdbUtils::makeTap(deviceId, node.x(), node.y());
                    QThread::msleep(QRandomGenerator::global()->bounded(200, 901));
                }
                // После ввода пин-код нужно сделать задержку, пока подгрузка идет, чтобы снова не спарсить
                findAndInputPincode = true;
                QThread::msleep(3000);
                continue;
            }
        }

        QThread::msleep(1000);

        // Если что-то пойдет не по плану...
        if (totalCounter > 100) {
            return false;
        }
    }
}

QString getPriceAsString(const double value) {
    QString sign = value < 0 ? "Минус" : "Плюс";
    const auto intValue = static_cast<qint64>(std::abs(value)); // округление до целого

    QString number = QString::number(intValue);
    QString formatted;

    int count = 0;
    for (int i = number.length() - 1; i >= 0; --i) {
        formatted.prepend(number[i]);
        ++count;
        if (count % 3 == 0 && i != 0) {
            formatted.prepend(' ');
        }
    }

    return QString("%1 %2").arg(sign, formatted);
}

Node swipeToButton(
    ScreenXmlParser &xmlScreenParser, const QString &deviceId,
    const QString &text, int &counter, const int width, const int height
) {
    for (int i = 0; i < 10; ++i) {
        if (Node button = xmlScreenParser.findButtonNode(text, true); button.x() > 0 && button.y() > 0) {
            return button;
        }
        const int x = width / 2;
        const int offset = height / 4;
        AdbUtils::makeSwipe(deviceId, x, height - offset, x, offset);
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
    }
    return {};
}

void HomeScreenScript::start() {
    // Достаем данные из БД по ИД транзакции, перед тем как запустить мы кладем в БД все данные
    const QString deviceId = "6edc4a47";
    const QString packageName = "ru.rshb.dbo";
    const QString pinCode = "1102";
    const int width = 720;
    const int height = 1600;

    const QString cardNumber = "7 1 8 3";
    // В том числе и данные на каком устройстве это делать
    // TODO тут код работы с БД

    // +7 (964) 181-51-46
    const QString phoneNumber = "+79641815146";
    const QString bankName = "Альфа-Банк";
    const QString paySum = "10";

    int index = 0;
    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++index));

    // xmlScreenParser.test();
    // тут просто получаем инфу которую спарсил
    // == 1. Входящий (TransactionType::Phone)
    // Перевод через СБП от Егор Иванович Ж (+7(000)-000-00-87) из Озон Банк (Ozon) на 40817810328000022077 .
    // Идентификатор операции в СБП С2С B5121111443333300170011491301 , Дата операции 01.05.2025 14:14:41 Статус перевода Исполнен
    // == 2. Исходящий (TransactionType::Phone)
    // Перевод Надежда Иванкина К** в Сбербанк через СБП, по номеру телефона +79000810046, ID перевода 445900141, дата 03.05.2025

    // (TransactionType::Card) -> T-BANK CARD2CARD
    // TransactionInfo trInfo = xmlScreenParser.parseTransactionInfoHistory(width, height);
    // qDebug().noquote().nospace() << convertTransactionToString(trInfo);

    // Если начинается с ЕСПП - то не кликаем еще, ждет обработку
    // А все переводы по карте - они не начинаются со слова "Перевод" ->
    // .. пробуем кликать, но если не кликается ???
    QList<TransactionInfo> transactions = xmlScreenParser.parseTodayAndYesterdayHistory();
    for (const TransactionInfo &info: transactions) {
        QString text = QString("%1 %2").arg(info.shortDescription, getPriceAsString(info.amount));
        qDebug().noquote().nospace() << convertTransactionToString(info);

        // Node trButton = xmlScreenParser.findButtonNode(text, true);
        Node trButton = swipeToButton(xmlScreenParser, deviceId, text, index, width, height);
        if (!trButton.isEmpty()) {
            AdbUtils::makeTap(deviceId, trButton.x(), trButton.y());
            QThread::msleep(500);

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++index));

            Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
            if (!moreDetailBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, moreDetailBtn.x(), moreDetailBtn.y());
                QThread::msleep(200);
                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++index));
                TransactionInfo info = xmlScreenParser.parseTransactionInfoHistory(width, height);
                qDebug().noquote().nospace() << convertTransactionToString(info);
            }

            AdbUtils::goBack(deviceId);
        } else {
            qWarning() << "--- trButton not found..........";
        }
        // Перевод ВЛАДИСЛАВ НИКОЛАЕВИЧ К** в Т-Банк через СБП, по номеру телефона +7985553... Минус 10 рублей 0 копеек
    }

    return;

    int payCounter = 0;

    if (false) {
        // Оплата со страницы карты
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        Node payBtn = xmlScreenParser.findButtonNode("Оплатить", false);
        if (!payBtn.isEmpty()) {
            AdbUtils::makeTap(deviceId, payBtn.x(), payBtn.y());
            QThread::msleep(1000);
        } else {
            qWarning() << "--- payBtn not found";
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        // TODO - По номеру карты В РСХБ и другие банки
        Node payTitle = xmlScreenParser.findTextNode("Платежи и переводы");
        if (!payTitle.isEmpty() && payTitle.y() < 300) {
            Node payByPhoneBtn = xmlScreenParser.findButtonNode("По номеру телефона В РСХБ и через", false);
            if (!payByPhoneBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, payByPhoneBtn.x(), payByPhoneBtn.y());
                QThread::msleep(1000);
            } else {
                qWarning() << "--- payByPhoneBtn not found";
            }
        } else {
            qWarning() << "--- payTitle not found";
        }


        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        Node payByPhoneTitle = xmlScreenParser.findTextNode("Перевод по телефону");
        Node continueBtn = xmlScreenParser.findButtonNode("Продолжить", false);
        if (!payByPhoneTitle.isEmpty() && payByPhoneTitle.y() < 300 && continueBtn.isEmpty()) {
            Node inputPhone = xmlScreenParser.findFirstEditText();
            AdbUtils::makeTap(deviceId, inputPhone.x(), inputPhone.y());
            QThread::msleep(500);
            AdbUtils::inputText(deviceId, phoneNumber);
            QThread::msleep(1000);
        } else {
            qWarning() << "--- payByPhoneTitle not found (no continueBtn)";
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        QString payBankName;
        payBankName = bankName == "Россельхозбанк" ? "Россельхозбанк" : "Другой банк через СБП";
        Node payOtherBankBtn = xmlScreenParser.findButtonNode(payBankName, false);
        if (!payOtherBankBtn.isEmpty()) {
            AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y());
            QThread::msleep(1000);
        } else {
            qWarning() << "--- payOtherBankBtn not found";
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        for (int i = 0; i < 5; ++i) {
            Node allBanksTitle = xmlScreenParser.findTextNode("Банки участники");
            if (!allBanksTitle.isEmpty() && allBanksTitle.y() < 300) {
                Node inputBankName = xmlScreenParser.findFirstEditText();
                AdbUtils::makeTap(deviceId, inputBankName.x(), inputBankName.y());
                QThread::msleep(500);
                AdbUtils::enableAdbIMEKeyboard(deviceId);
                AdbUtils::inputAdbIMEText(deviceId, bankName);
                AdbUtils::disableAdbIMEKeyboard(deviceId);
                QThread::msleep(1000);
                break;
            } else {
                qWarning() << "--- allBanksTitle not found, i: " << i;
            }
            QThread::msleep(1000);
            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        for (int i = 0; i < 5; ++i) {
            Node bankNameListItem = xmlScreenParser.findTextNode(bankName);
            if (!bankNameListItem.isEmpty()) {
                AdbUtils::makeTap(deviceId, bankNameListItem.x(), bankNameListItem.y());
                QThread::msleep(1000);
                break;
            } else {
                qWarning() << "--- bankNameListItem not found, i: " << i;
            }
            QThread::msleep(1000);
            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));

        Node payByPhoneScreenTitle = xmlScreenParser.findTextNode("Перевод по телефону");
        Node continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);
        if (!payByPhoneScreenTitle.isEmpty() && payByPhoneScreenTitle.y() < 300 && !continuePayBtn.isEmpty()) {
            Node sumBtn = xmlScreenParser.findButtonNode("0", false);
            if (!sumBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, sumBtn.x(), sumBtn.y());
                QThread::msleep(500);
                AdbUtils::inputText(deviceId, paySum);
                QThread::msleep(500);

                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
                Node readyBtn = xmlScreenParser.findTextNode("Готово");
                if (!readyBtn.isEmpty()) {
                    AdbUtils::makeTap(deviceId, readyBtn.x(), readyBtn.y());
                    QThread::msleep(500);
                    AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y());
                    QThread::msleep(1000);
                } else {
                    qWarning() << "--- readyBtn not found";
                }
            } else {
                qWarning() << "--- sumBtn not found";
            }
        } else {
            qWarning() << "--- payByPhoneScreenTitle not found";
        }

        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        for (int i = 0; i < 5; ++i) {
            // TODO кнопка содержит "Перевести 10 ₽" если будет от 1000 то скорее всвего будет "Перевести 1 000 ₽",
            // TODO не ясно как форматирование будет, поэтому пока на начало зашьем
            Node makePayBtn = xmlScreenParser.findButtonNode("Перевести ", true);
            if (!makePayBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, makePayBtn.x(), makePayBtn.y());
                QThread::msleep(500);

                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
                if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите код доступа");
                    pincode.size() == 4) {
                    // FIXME вынести в отдельный метод
                    // делаем 4 тапа и ждем секунду и продолжаем
                    for (const Node &node: pincode) {
                        AdbUtils::makeTap(deviceId, node.x(), node.y());
                        QThread::msleep(QRandomGenerator::global()->bounded(200, 901));
                    }

                    // После ввода пин-кода, ждем 3с
                    QThread::msleep(3000);
                }
                break;
            } else {
                qWarning() << "--- makePayBtn not found, i: " << i;
            }
            QThread::msleep(1000);
            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
        }
    }

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));

    for (int i = 0; i < 5; ++i) {
        Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
        if (!moreDetailBtn.isEmpty()) {
            AdbUtils::makeTap(deviceId, moreDetailBtn.x(), moreDetailBtn.y());
            QThread::msleep(200);
            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));

            Node paymentCompleted = xmlScreenParser.findTextNode("Исполнен", 0, 0, width, height / 2);
            Node paymentInProgress = xmlScreenParser.findTextNode("Выполняется", 0, 0, width, height / 2);

            if (!paymentCompleted.isEmpty()) {
                // Если вдруг исполнен
            } else if (!paymentInProgress.isEmpty()) {
                // Если все еще в ожидании
            } else {
                qWarning() << "--- paymentCompleted or paymentInProgress not found...";
            }
            break;
        } else {
            qWarning() << "--- moreDetailBtn not found, i: " << i;
        }

        QThread::msleep(1000);
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++payCounter));
    }


    return;

    int counter = 0;
    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, counter));
    Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(width, height);
    if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) {
        qDebug() << "--- tryToFindBannerOrDialog";
        AdbUtils::makeTap(deviceId, closeBannerOrDialogNode.x(), closeBannerOrDialogNode.y());
        QThread::msleep(1000);
    }
    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
    if (xmlScreenParser.isHomeScreen()) {
        qDebug() << "--- isHomeScreen";
        if (Node allCardTitle = xmlScreenParser.findTextNode("Счета и карты"); !allCardTitle.isEmpty()) {
            // 1. Если нет кнопки видимой, свайпаем. Кликаем на "Все продукты"
            for (int i = 0; i < 5; ++i) {
                Node allProductsBtn = xmlScreenParser.findButtonNode("Все продукты", false);
                // Node allProductsBtn = xmlScreenParser.findTextNode("Курсы валют и металлов"); для теста
                if (allProductsBtn.x() > 0 && allProductsBtn.y() > 0) {
                    qDebug() << "--- All Product in focus";
                    AdbUtils::makeTap(deviceId, allProductsBtn.x(), allProductsBtn.y());
                    QThread::msleep(1000);
                    break;
                }
                AdbUtils::makeSwipe(deviceId,
                                    allCardTitle.x(), allCardTitle.y(),
                                    allCardTitle.x(), allCardTitle.y() - 200);
                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            }

            for (int i = 0; i < 5; ++i) {
                Node allProductsTitle = xmlScreenParser.findTextNode("Все продукты");
                // Проверяем что вверху заголовок
                if (!allProductsTitle.isEmpty() && allProductsTitle.y() < 300) {
                    qDebug() << "--- All Product screen";

                    // TODO тут делаем синхронизацию данных все карт

                    Node cardNumberBtn = xmlScreenParser.findButtonNode(cardNumber, true);
                    AdbUtils::makeTap(deviceId, cardNumberBtn.x(), cardNumberBtn.y());
                    break;
                }

                QThread::msleep(1000);
                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            }

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            Node filterBtn = xmlScreenParser.findButtonNode("РСХБ Онлайн", false);
            if (!filterBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, filterBtn.x(), filterBtn.y());
                QThread::msleep(1000);
            } else {
                qWarning() << "--- filterBtn not found";
            }

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            Node allTransactionFilerBtn = xmlScreenParser.findButtonNode("Все операции", false);
            if (!allTransactionFilerBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, allTransactionFilerBtn.x(), allTransactionFilerBtn.y());
                QThread::msleep(1000);
            } else {
                qWarning() << "--- allTransactionFilerBtn not found";
            }

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            for (int i = 0; i < 5; ++i) {
                QList<Node> transactions = xmlScreenParser.getLast2DaysTransactions();
                if (!transactions.empty()) {
                    for (const Node &transaction: transactions) {
                        qDebug() << transaction.text;
                        // TODO вот мы дошли до списка транзакций
                    }
                    break;
                }

                QThread::msleep(1000);
                xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
            }

            //
        } else {
            // пишем в БД, что не дошли до домашней страницы, и завершаемся
            // сохраняем скрин приложения
            // дделаем алерт
        }
    } else {
        // пишем в БД, что не дошли до домашней страницы, и завершаемся
        // сохраняем скрин приложения
        // дделаем алерт
    }

    return;

    // 1. Идем на домашнюю страницу
    if (goToHomeScreen(deviceId, packageName, pinCode, width, height)) {
        // мы на главном
        // перед тем как юзать снова проверить на банеры
        // Проверяем на банеры после пин-кодом


        // Это уже для шага дальше
        //  если нулевые координаты, свайпаем вверх, чтобы текст "Счета и карты" был у верхнего края
    } else {
        // пишем в БД, что не дошли до домашней страницы, и завершаемся
        // сохраняем скрин приложения
        // дделаем алерт
    }

    // 2. Идем дальше


    emit finished();
}


void HomeScreenScript::stop() {
    m_running = false;
}
