//
// Created by AmirS on 24.04.2025.
//

#include "Script.h"
#include "AdbUtils.h"
#include "XmlParser.h"
#include "QDebug"
#include <regex>

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

Script::~Script() = default;

void Script::start() {
    qDebug() << "Worker started in thread:" << QThread::currentThread();

    processUiLoop();
}

[[noreturn]] void Script::processUiLoop() {
    qDebug() << QString::fromUtf8("Запуск скрипта для ru.rshb.dbo");

    if (!AdbUtils::checkDevices()) {
        qDebug() << QString::fromUtf8("ADB: Нет устройств");
        return;
    }

    if (!AdbUtils::startApp("ru.rshb.dbo")) {
        qDebug("Не удалось запустить приложение");
        return;
    }

    QThread::msleep(4500);
    while (true) {
        QString uiDumpPath = "ui_dump.xml";
        AdbUtils::dumpAndPullUiXml(uiDumpPath);

        QList<UiElement> elements = XmlParser::parseUiDumpUsingQXml(uiDumpPath);

        switch (currentState) {
            case State::HandlingSecurityBanner:
                handleSecurityBanner(elements);
                // Переход в состояние ожидания ПИН-кода после закрытия баннера
                currentState = State::WaitingForPinInput;

            case State::WaitingForPinInput:
                if (XmlParser::isPinCodeScreen(elements)) {
                    qDebug() << "Экран ввода ПИН-кода обнаружен";
                    inputPinCode("1211");
                    currentState = State::ClosingBanner;
                }
                break;

            case State::ClosingBanner:
                handleClosingBanner(elements);
                break;

            case State::OnMainScreen:
                if (XmlParser::isMainScreen(elements)) {
                    qDebug() << "State: OnMainScreen -> Поиск кнопки 'Все продукты'";
                    swipeToFindElement("Все продукты");
                    currentState = State::SearchingCard;
                }
                break;

            case State::SearchingCard:
                qDebug() << "State: SearchingCard -> Поиск блока карты";
            // Добавить сюда поиск карты по последним 4 цифрам, известным заранее, для выбора карты
                // currentState = State::OnCardDetails;
                currentState = State::Idle;
                break;

            case State::OnCardDetails:
                // Обработка экрана деталей банковской карты
                handleCardDetailsScreen(elements);
                break;

            case State::OnTransferScreen:
                qDebug() << "State: OnTransferScreen -> Перевод выполнен успешно.";
                // handleTransferScreen(elements);
                currentState = State::Idle;
                break;

            case State::Idle:
            default:
                qDebug() << "State: Idle -> Жду следующего действия";
                if (XmlParser::isSecurityBanner(elements)) {
                    currentState = State::HandlingSecurityBanner;
                } else if (XmlParser::isPinCodeScreen(elements)) {
                    currentState = State::WaitingForPinInput;
                }
                break;
        }

        QThread::msleep(1000); // Пауза между проверками экрана
    }
}


// Функция для запуска скрипта с передачей параметров
// void Script::runScript(const QString& pin, const QString& last4digits) {
//     qDebug("Запуск скрипта для ru.rshb.dbo");
//
//     if (!AdbUtils::checkDevices()) {
//         qDebug("ADB: Нет устройств");
//         return;
//     }
//
//     if (!AdbUtils::startApp("ru.rshb.dbo")) {
//         qDebug("Не удалось запустить приложение");
//         return;
//     }
//
//     wait(4500);
//     AdbUtils::dumpAndPullUiXml("ui_01.xml");
//
//     auto ui = XmlParser::parseUiDumpUsingQXml("ui_01.xml");
//
//     if (XmlParser::isPinCodeScreen(ui)) {
//         qDebug("Экран PIN-кода");
//
//         // Находим координаты цифр на экране и вводим ПИН
//         std::vector<UiElement> pinButtons = getPinButtons(ui);
//         for (size_t i = 0; i < pin.length(); ++i) {
//             char digit = pin[i];
//             for (const auto& el : pinButtons) {
//                 if (el.text == std::string(1, digit)) {
//                     AdbUtils::tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
//                     break;
//                 }
//             }
//         }
//         wait(1000);
//     }
//
//     // Появляющиеся после входа по ПИН баннеры — цикл для обработки разных состояний показов модальных окон
//     bool postLoginScreenFound = false;
//     int attempts = 5;  // Максимальное количество попыток парсинга xml
//     while (attempts-- > 0) {
//         AdbUtils::dumpAndPullUiXml("ui_02.xml");
//         auto ui2 = XmlParser::parseUiDumpUsingQXml("ui_02.xml");
//
//         // Закрытие баннеров или диалогов
//         if (handlePostLoginScreen(ui2)) {
//             postLoginScreenFound = true;
//             break;
//         }
//
//         // Проверка, если мы на главном экране
//         if (isMainScreen(ui2)) {
//             qDebug("Главный экран подтверждён");
//             postLoginScreenFound = true;
//             break;
//         }
//
//         // Ждем немного перед следующим запросом дампа экрана
//         wait(1000);
//     }
//
//     if (!postLoginScreenFound) {
//         qDebug("Не удалось определить пост-логин баннер.");
//         return;
//     }
//
//     // Пролистывание до кнопки "Все продукты"
//     AdbUtils::swipe(1000, 2000, 1000, 1300);
//     wait(500);
//
//     // Нажимаем на кнопку "Все продукты"
//     AdbUtils::dumpAndPullUiXml("ui_03.xml");
//     auto ui3 = XmlParser::parseUiDumpUsingQXml("ui_03.xml");
//
//     // Ищем кнопку "Все продукты" и нажимаем на неё
//     tapByText(ui3, "Все продукты");
//     wait(800);
//
//     // Шаг 6: Выбор карты на экране "Все продукты"
//     // Запрашиваем дамп UI для поиска карт
//     AdbUtils::dumpAndPullUiXml("ui_04.xml");
//     auto ui4 = XmlParser::parseUiDumpUsingQXml("ui_04.xml");
//
//     // Определим, какую карту выбрать, например, с 4 цифрами "0823"
//     UiElement cardButton = findCardByLast4Digits(ui4, last4digits);
//     if (cardButton.text.isEmpty()) {
//         qDebug("Не найдена карта с номером, содержащим " + last4digits);
//         return;
//     }
//
//     // Нажимаем на карту
//     AdbUtils::tap((cardButton.x1 + cardButton.x2) / 2, (cardButton.y1 + cardButton.y2) / 2);
//     wait(1000);
//
//     // Нажимаем на кнопку "Оплатить"
//     // Запрашиваем дамп UI для поиска кнопки "Оплатить"
//     AdbUtils::dumpAndPullUiXml("ui_05.xml");
//     auto ui5 = XmlParser::parseUiDumpUsingQXml("ui_05.xml");
//
//     // Ищем кнопку "Оплатить" и нажимаем на неё
//     UiElement payBtn = findPayButton(ui5);
//     if (payBtn.text.isEmpty()) {
//         qDebug("Не найдена кнопка 'Оплатить'");
//         return;
//     }
//
//     // Нажимаем на кнопку "Оплатить"
//     AdbUtils::tap((payBtn.x1 + payBtn.x2) / 2, (payBtn.y1 + payBtn.y2) / 2);
//     qDebug("Нажата кнопка 'Оплатить'");
//     wait(1000);
// }

// Вспомогательные функции

// Функция для нажатия по элементу, передавая элемент
void tapElement(const UiElement &el) {
    const int x = (el.x1() + el.x2()) / 2;
    const int y = (el.y1() + el.y2()) / 2;
    // Тапаем по кнопке
    AdbUtils::tap(x, y);
}

// Функции для определения экранов и действий

void Script::handleSecurityBanner(const QList<UiElement>& elements) {
    if (XmlParser::isSecurityBanner(elements)) {
        qDebug() << "State: HandlingSecurityBanner -> Найден баннер о безопасности.";

        // Ищем кликабельную кнопку "Отложить"
        for (const UiElement& el : elements) {
            if (el.text() == "Отложить" && el.isClickable() && el.className() == "android.widget.Button") {
                qDebug() << "Найдена кнопка 'Отложить'. Нажимаем её!";
                tapElement(el);  // Нажимаем на кнопку "Отложить"
                break;
            }
        }
    }
}

void Script::inputPinCode(const QString &pinCode) {
    // Перебираем каждый символ из ПИН-кода
    for (int i = 0; i < pinCode.length(); ++i) {
        QString digit = pinCode.mid(i, 1);
        qDebug() << "Найдена кнопка для символа: " << digit;

        // Поиск кнопки с соответствующим текстом
        QList<UiElement> elements = XmlParser::parseUiDumpUsingQXml("ui_dump.xml");

        // Ищем кнопку с цифрой
        bool found = false;
        for (const UiElement &el: elements) {
            if (el.text() == digit && el.isClickable()) {
                tapElement(el);
                found = true;
                break;
            }
        }

        // Если не нашли кнопку для цифры, выводим предупреждение
        if (!found) {
            qWarning() << "Цифровая кнопка для " << digit << " не найдена!";
        }

        // Пауза между нажатиями, чтобы избежать слишком быстрого ввода
        QThread::msleep(200);
    }
}

void Script::handleClosingBanner(const QList<UiElement> &elements) {
    while (true) {
        // Проверка на наличие баннера или диалога
        if (XmlParser::isBannerOrDialog(elements)) {
            qDebug() << "State: ClosingBanner -> Найден баннер/диалог. Закрываем его.";

            // Флаг для отслеживания, если мы нашли хотя бы одно окно для закрытия
            bool closed = false;

            for (const UiElement &el: elements) {
                if (el.isClickable()) {
                    // Пробуем закрыть баннер, если есть кнопка "Закрыть"
                    if ((el.text() == "Закрыть" || el.text() == "Позже") && el.className() == "android.widget.Button") {
                        tapElement(el);
                        closed = true;
                        qDebug() << "Баннер/диалог закрыт!";
                        break;
                    }
                    // Если кнопка без текста и в правой верхней части (проверяем по координатам приблизительно)
                    if (el.text().isEmpty() && el.className() == "android.widget.Button" &&
                        el.x1() > 800 && el.y1() < 200) {
                        tapElement(el);
                        closed = true;
                        qDebug() << "Баннер/диалог закрыт по нажатию кнопки в правом верхнем углу.";
                        break;
                    }
                }
            }

            if (!closed) {
                qWarning() << "Невозможно закрыть баннер или диалог!";
                break; // Прерываем цикл, если не удалось закрыть окно
            }

            // Пауза перед следующим закрытием окна
            QThread::msleep(1000);
        } else {
            qDebug() << "State: ClosingBanner -> Не осталось баннеров/диалогов для закрытия.";
            // Заканчиваем цикл, если баннеров/диалогов больше нет
            break;
        }
    }

    // Переход к следующему состоянию
    // Если все модальные окна закрыты, переходим к основному экрану
    currentState = State::OnMainScreen;
}

void Script::swipeToFindElement(const QString &searchText) {
    bool found = false;
    int attempts = 0;

    // Прокручиваем экран несколько раз, пока не найдем элемент или не превысим попытки
    while (attempts < 5 && !found) {
        QList<UiElement> elements = XmlParser::parseUiDumpUsingQXml("ui_dump.xml");

        // Ищем нужный элемент на экране и если он найден - нажимаем на него
        for (const UiElement &el: elements) {
            if (el.text() == searchText && el.isClickable() && el.className() == "android.widget.Button") {
                qDebug() << "Найден элемент: " << searchText;
                tapElement(el);
                found = true;
                break;
            }
        }

        // Если элемент не найден, выполняем свайп, прибавляем попытку и ищем снова
        if (!found) {
            qDebug() << "Элемент не найден, свайпаем...";
            // Свайп вверх
            AdbUtils::swipe(500, 1500, 500, 500);
            attempts++;
            // Пауза между свайпами
            QThread::msleep(1000);
        }
    }

    if (!found) {
        qWarning() << "Элемент " << searchText << " не найден после " << attempts << " попыток свайпа.";
    }
}

void Script::handleCardDetailsScreen(const QList<UiElement>& elements) {
    // Проверяем, что мы на экране детали карты
    if (XmlParser::isDetailCardScreen(elements)) {
        qDebug() << "State: OnCardDetails -> Найден экран детализированной карты.";

        // Ищем кликабельную кнопку "Оплатить"
        bool foundPaymentButton = false;
        for (const UiElement& el : elements) {
            if (el.text() == "Оплатить" && el.isClickable()) {
                qDebug() << "Найдена кнопка 'Оплатить'. Нажимаем её!";
                // Нажимаем на кнопку "Оплатить"
                tapElement(el);
                foundPaymentButton = true;
                break;
            }
        }

        if (!foundPaymentButton) {
            qWarning() << "Payment button 'Оплатить' not found on the card details screen.";
        }
    }
}

// void Script::handleTransferScreen(const QList<UiElement> &elements) {
//     // Проверка на экран перевода
//     if (XmlParser::isTransferScreen(elements)) {
//         qDebug() << "State: OnTransferScreen -> Looking for 'Enter amount' field or 'Confirm' button.";
//
//         bool found = false;
//
//         // Если поле для ввода суммы найдено, вводим сумму
//         for (const UiElement &el: elements) {
//             if (el.text() == "Сумма" && el.isClickable()) {
//                 qDebug() << "Found 'Amount' input field";
//                 inputAmount("1000"); // Пример суммы
//                 found = true;
//                 break;
//             }
//         }
//
//         if (!found) {
//             qDebug() << "Поле ввода 'Сумма' не найдено!";
//         }
//
//         // После ввода суммы ищем кнопку 'Оплатить' или 'Подтвердить'
//         for (const UiElement &el: elements) {
//             if ((el.text() == "Оплатить" || el.text() == "Подтвердить") && el.isClickable()) {
//                 tapElement(el);
//                 qDebug() << "Payment confirmed.";
//                 break;
//             }
//         }
//     }
// }

void Script::inputAmount(const QString &amount) {
    // Разделяем сумму на отдельные цифры
    for (int i = 0; i < amount.length(); ++i) {
        QString digit = amount.mid(i, 1);
        qDebug() << "Вводим цифру: " << digit;

        // Поиск кнопки с соответствующей цифрой
        QList<UiElement> elements = XmlParser::parseUiDumpUsingQXml("ui_dump.xml");

        bool found = false;
        for (const UiElement &el: elements) {
            if (el.text() == digit && el.isClickable()) {
                tapElement(el);
                found = true;
                break;
            }
        }

        if (!found) {
            qWarning() << "Цифровая кнопка для " << digit << " не найдена!";
        }

        QThread::msleep(1000); // Пауза между нажатиями
    }

    // Если нужно, нажимаем кнопку для завершения ввода суммы
    QList<UiElement> elements = XmlParser::parseUiDumpUsingQXml("ui_dump.xml");
    for (const UiElement &el: elements) {
        if (el.isClickable()) {
            if (el.text() == "ОК" || el.text() == "Подтвердить" || el.text() == "Готово") {
                tapElement(el);
                break;
            }
        }
    }
}

// void tapByText(const std::vector<UiElement> &ui, const std::string &text) {
//     for (const auto &el: ui) {
//         if (el.text == QString::fromStdString(text)) {
//             tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
//             break;
//         }
//     }
// }
//
// // Тап по полю ввода
// void tapInputField(const std::vector<UiElement> &ui, const std::string &fieldText) {
//     for (const auto &el: ui) {
//         if (el.text == QString::fromStdString(fieldText)) {
//             tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
//             break;
//         }
//     }
// }
//
// // Тап по кнопке "Далее"
// void tapNextButton(const std::vector<UiElement> &ui) {
//     for (const auto &el: ui) {
//         if (el.text == "Войти" || el.text == "Далее" || el.text == "Продолжить") {
//             tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
//             break;
//         }
//     }
// }
//
// UiElement findCardByLast4Digits(const std::vector<UiElement> &ui, const std::string &last4digits) {
//     // Проходим по всем элементам UI, которые парсились из XML
//     for (const auto &el: ui) {
//         // Используем регулярное выражение для поиска 4 цифр в тексте
//         std::smatch m;
//         std::string str = el.text.toUtf8().constData(); // Преобразуем QString в std::string
//
//         // Если в тексте найдено совпадение с регулярным выражением для 4 цифр
//         if (std::regex_search(str, m, std::regex(R"(\*\*\s?(\d{4}))"))) {
//             // Проверяем, совпадают ли последние 4 цифры с переданными
//             if (m[1] == last4digits) {
//                 // Если нашли совпадение, возвращаем элемент
//                 return el;
//             }
//         }
//     }
//
//     // Если карта с такими последними цифрами не найдена, возвращаем пустой элемент
//     return {};
// }
//
// UiElement findPayButton(const std::vector<UiElement> &ui) {
//     for (const auto &el: ui) {
//         if (el.text == "Оплатить") {
//             return el;
//         }
//     }
//     return {};
// }

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