#include "PayByPhoneScript.h"

#include <QRandomGenerator>
#include <QThread>
#include <utility>

#include "DatabaseManager.h"
#include "adb/AdbUtils.h"
#include "dao/AccountDAO.h"
#include "dao/ApplicationDAO.h"
#include "dao/DeviceDAO.h"
#include "dao/TransactionDAO.h"
#include "db/ApplicationInfo.h"
#include "db/DeviceInfo.h"

PayByPhoneScript::PayByPhoneScript(
    AccountInfo account,
    QString phone,
    QString bankName,
    const double amount,
    QObject *parent
) : CommonScript(parent),
    m_account(std::move(account)), m_phone(std::move(phone)),
    m_bankName(std::move(bankName)), m_amount(amount) {
}

PayByPhoneScript::~PayByPhoneScript() = default;


void PayByPhoneScript::makePayment(
    const QString &deviceId,
    const QString &pinCode,
    int width,
    int height
) {
    // Оплата со страницы карты
    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    Node payBtn = xmlScreenParser.findButtonNode("Оплатить", false);
    if (!payBtn.isEmpty()) {
        AdbUtils::makeTap(deviceId, payBtn.x(), payBtn.y());
        QThread::msleep(1000);
    } else {
        m_error = "Кнопка 'Оплатить' не нашлась";
        qDebug() << m_error;
        return;
    }

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    // 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 {
            m_error = "Не смогли найти пункт 'По номеру телефона В РСХБ и через'";
            qDebug() << m_error;
            return;
        }
    } else {
        m_error = "Не смогли перейти на экран 'Платежи и переводы'";
        qDebug() << m_error;
        return;
    }


    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    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, m_phone);
        QThread::msleep(1000);
    } else {
        m_error = "Не смогли найти пункт 'Перевод по телефону'";
        qDebug() << m_error;
        return;
    }

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    QString payBankName = m_bankName == QStringLiteral("Россельхозбанк") ? "Россельхозбанк" : "Другой банк через СБП";
    Node payOtherBankBtn = xmlScreenParser.findButtonNode(payBankName, false);
    if (!payOtherBankBtn.isEmpty()) {
        AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y());
        QThread::msleep(1000);
    } else {
        m_error = "Не смогли нажать на первичный выбор банка";
        qDebug() << m_error;
        return;
    }

    if (m_bankName != QStringLiteral("Россельхозбанк")) {
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
        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, m_bankName);
                AdbUtils::disableAdbIMEKeyboard(deviceId);
                QThread::msleep(1000);
                break;
            } else {
                qDebug() << "--- allBanksTitle not found, i: " << i;
            }
            QThread::msleep(1000);
            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
        }

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

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

    const bool isRshbBank = m_bankName == QStringLiteral("Россельхозбанк");
    QString payByPhoneScreenTitleText = isRshbBank ? "Перевод клиенту РСХБ" : "Перевод по телефону";
    Node payByPhoneScreenTitle = xmlScreenParser.findTextNode(payByPhoneScreenTitleText);
    Node continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);

    if (isRshbBank ||
        !payByPhoneScreenTitle.isEmpty() && payByPhoneScreenTitle.y() < 300 && !continuePayBtn.isEmpty()) {
        Node sumBtn = xmlScreenParser.findButtonNode("0", false);
        if (isRshbBank || !sumBtn.isEmpty()) {
            if (!isRshbBank) {
                AdbUtils::makeTap(deviceId, sumBtn.x(), sumBtn.y());
                QThread::msleep(500);
            }
            AdbUtils::inputText(deviceId, QString::number(m_amount));
            QThread::msleep(500);

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
            Node readyBtn = xmlScreenParser.findTextNode("Готово");
            if (!readyBtn.isEmpty()) {
                AdbUtils::makeTap(deviceId, readyBtn.x(), readyBtn.y());
                QThread::msleep(500);
                if (isRshbBank) {
                    QThread::msleep(1000);
                    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
                    continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);
                }
                AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y());
                QThread::msleep(1000);
            } else {
                m_error = "Не смогли нажать 'Готово'";
                qDebug() << m_error;
                return;
            }
        } else {
            m_error = "Не смогли нажать 'Продолжить'";
            qDebug() << m_error;
            return;
        }
    } else {
        m_error = "Не смогли найти заголовок: " + payByPhoneScreenTitleText;
        qDebug() << m_error;
        return;
    }

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    bool inputedPinCode = false;
    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, ++m_counter));
            if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите код доступа");
                pincode.size() == 4) {
                inputPinCode(deviceId, pincode);
                inputedPinCode = true;
                // После ввода пин-кода, ждем 3с
                QThread::msleep(3000);
            }
            break;
        } else {
            qWarning() << "--- makePayBtn not found, i: " << i;
        }
        QThread::msleep(1000);
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    }

    if (!isRshbBank && !inputedPinCode) {
        m_error = "Не смогли ввести пин-код!'";
        qDebug() << m_error;
        return;
    }

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

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

            // TODO считываем все данные по переводу
            TransactionInfo transaction = xmlScreenParser.parseTransactionInfo(width, height);
            if (isRshbBank) {
                transaction.bankName = m_bankName;
            }
            transaction.accountId = m_account.id;
            transaction.amount = -m_amount;
            transaction.type = TransactionType::Phone;
            transaction.id = TransactionDAO::insertTransaction(transaction);
            if (transaction.id == -1) {
                // FIXME alert!!
                qDebug() << "Transaction has not inserted...";
            }

            // ждем 10 секунд смену статуса
            for (int k = 0; k < 10; ++k) {
                Node paymentCompleted = xmlScreenParser.findTextNode("Исполнен", 0, 0, width, height / 2);
                if (!paymentCompleted.isEmpty()) {
                    transaction.status = TransactionStatus::Complete;
                    if (!TransactionDAO::updateTransactionStatus(transaction.id, TransactionStatus::Complete)) {
                        qDebug() << "Not updated: " << transaction.id;
                    }
                    // TODO обновляем данные
                    break;
                }

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

            postNewTransactionData(m_account, transaction);
            break;
        } else {
            qWarning() << "--- moreDetailBtn not found, i: " << i;
        }
        QThread::msleep(1000);
        xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
    }

    Node homeBtn = xmlScreenParser.findButtonNode("Вернуться на главную", false);
    AdbUtils::makeTap(deviceId, homeBtn.x(), homeBtn.y());
    QThread::msleep(1000);
}

void PayByPhoneScript::doStart() {
    const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
    const ApplicationInfo app = ApplicationDAO::getApplicationsByDeviceId(m_account.deviceId, m_account.appName);

    if (device.id.isEmpty() || app.id.isEmpty()) {
        m_error = "Device or app not found....";
        qDebug() << m_error;
        emit finishedWithResult(m_error);
        return;
    }

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
    if (!xmlScreenParser.isHomeScreen()) {
        if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) {
            m_error = "Не смогли дойти до домашней страницы....";
            qDebug() << m_error;
            emit finishedWithResult(m_error);
            return;
        }
    }

    if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
        qDebug() << "======== 1. All products";
        QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
        for (auto &[account, node]: accounts) {
            account.deviceId = m_account.deviceId;
            account.appName = m_account.appName;
            if (!AccountDAO::upsertAccount(account)) {
                qDebug() << "Not updated: " << account.lastNumbers;
            }
        }

        postAccountsData(accounts);

        for (auto &[account, node]: accounts) {
            // FIXME будем считать что числа последние везде уникальные
            if (m_account.lastNumbers == account.lastNumbers) {
                qDebug() << "======== 2. Tap by card";
                AdbUtils::makeTap(device.id, node.x(), node.y());
                QThread::msleep(1000);
                break;
            }
        }

        qDebug() << "======== 3. Make payment";
        makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight);
    } else {
        m_error = "Не смогли открыть 'Все продукты'";
        qDebug() << m_error;
    }

    emit finishedWithResult(m_error);
}
