#include "GetLastDaysHistoryScript.h"

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

#include "DatabaseManager.h"
#include "adb/AdbUtils.h"
#include "dao/AccountDAO.h"
#include "dao/DeviceDAO.h"
#include "dao/TransactionDAO.h"
#include "db/DeviceInfo.h"
#include "net/NetworkService.h"
#include "time/DateUtils.h"

GetLastDaysHistoryScript::GetLastDaysHistoryScript(
    AccountInfo account,
    QObject *parent
) : CommonScript(parent),
    m_account(std::move(account)) {
}

GetLastDaysHistoryScript::~GetLastDaysHistoryScript() = default;

QList<TransactionInfo> findSavedTransaction(
    const QList<TransactionInfo> &transactions,
    const TransactionInfo &parsed
) {
    QList<TransactionInfo> txs;
    const QDateTime dateTime = QDateTime::fromString(parsed.bankTime, "dd.MM.yyyy"); // Московское время

    for (const TransactionInfo &info: transactions) {
        QDateTime timestamp = info.timestamp;
        QString shortDescription = parsed.shortDescription;
        // если тот же день
        if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) {
            // Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
            if (shortDescription.contains("Перевод")) {
                if (shortDescription.contains(info.name)) {
                    txs.append(info);
                }
            } else {
                // Перевод по карте
                if (shortDescription == info.shortDescription) {
                    txs.append(info);
                }
            }
        }
    }

    return txs;
}

int countSimilar(const TransactionInfo &transaction, const QList<TransactionInfo> &transactions) {
    int count = 0;
    for (const TransactionInfo &info: transactions) {
        if (info.amount == transaction.amount
            && info.shortDescription == transaction.shortDescription
            && info.bankTime == transaction.bankTime) {
            ++count;
        }
    }
    return count;
}

QString formatPrice(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);
}

// bool GetLastDaysHistoryScript::openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height) {
//     QString text = QString("%1 %2").arg(transaction.shortDescription, formatPrice(transaction.amount));
//
//     Node trButton = swipeToButton(m_account.deviceId, text, m_counter, width, height);
//     if (!trButton.isEmpty()) {
//         AdbUtils::makeTap(m_account.deviceId, trButton.x(), trButton.y());
//         QThread::msleep(500);
//
//         xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
//
//         Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
//         if (!moreDetailBtn.isEmpty()) {
//             AdbUtils::makeTap(m_account.deviceId, moreDetailBtn.x(), moreDetailBtn.y());
//             QThread::msleep(200);
//             xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
//             TransactionInfo info = xmlScreenParser.parseTransactionInfoHistory(width, height);
//
//             if (transaction.id == -1) {
//                 info.accountId = m_account.id;
//                 info.shortDescription = transaction.shortDescription;
//                 info.amount = transaction.amount;
//                 info.type = info.phone.isEmpty() ? TransactionType::Card : TransactionType::Phone;
//                 info.updateTime = DateUtils::getUtcNow();
//                 if (info.status == TransactionStatus::Complete) {
//                     info.completeTime = DateUtils::getUtcNow();
//                 }
//                 if (TransactionDAO::insertTransaction(info) == -1) {
//                     qWarning() << "--- insertTransaction failed";
//                 }
//             } else {
//                 transaction.status = info.status;
//                 transaction.description = info.description;
//                 if (transaction.trExternalId.isEmpty()) {
//                     transaction.trExternalId = info.trExternalId;
//                 }
//                 transaction.updateTime = DateUtils::getUtcNow();
//                 if (transaction.status == TransactionStatus::Complete && !transaction.completeTime.isValid()) {
//                     transaction.completeTime = DateUtils::getUtcNow();
//                 }
//                 if (!TransactionDAO::updateTransaction(transaction)) {
//                     qWarning() << "--- updateTransaction failed";
//                 }
//             }
//         }
//
//         AdbUtils::goBack(m_account.deviceId);
//         QThread::msleep(200);
//     } else {
//         qWarning() << "--- trButton not found..........";
//     }
//     return false;
// }

bool GetLastDaysHistoryScript::saveAndPostNewTransactionData(
    const AccountInfo &account,
    const TransactionInfo &transaction
) {
    TransactionInfo tr;
    tr.accountId = account.id;
    tr.description = transaction.description;
    tr.bankTime = transaction.bankTime;
    tr.bankName = transaction.bankName;
    tr.amount = transaction.amount;
    tr.phone = transaction.phone;
    tr.updateTime = DateUtils::getUtcNow();
    tr.fee = transaction.fee;
    tr.name = transaction.name;
    tr.bankTrExternalId = transaction.bankTrExternalId;
    tr.status = TransactionStatus::Complete;
    tr.type = transaction.description.startsWith("Перевод") ? TransactionType::Phone : TransactionType::Card;
    tr.completeTime = DateUtils::getUtcNow();
    tr.id = TransactionDAO::insertTransaction(tr);

    if (tr.id == -1) {
        return false;
    }
    postNewTransactionData(account, tr);
    return true;
}

bool GetLastDaysHistoryScript::updateAndPostTransactionData(
    const AccountInfo &account,
    const int transactionId,
    const TransactionStatus status,
    const QString &oldDesc,
    const QString &newDesc
) {
    if (TransactionDAO::updateTransaction(transactionId, status, oldDesc, newDesc)) {
        updateTransactionData(account, transactionId, status, oldDesc, newDesc);
        return true;
    }
    return false;
}

void GetLastDaysHistoryScript::doStart() {

    return;

    // берем все транзакции из БД
    QList<TransactionInfo> localTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48);
    const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);

    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
    if (xmlScreenParser.isHomeScreen()) {
        if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
            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);

            findAndTapOnAccount(device.id, m_account.lastNumbers);

            xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
            Node actionBtn = xmlScreenParser.findButtonNode("Действия", false);
            if (!actionBtn.isEmpty()) {
                AdbUtils::makeTap(m_account.deviceId, actionBtn.x(), actionBtn.y());
                QThread::msleep(200);
            } else {
                qWarning() << "--- actionBtn not found";
            }
            Node reportButton = swipeToButton(m_account.deviceId, "Выписка", m_counter, device.screenWidth,
                                              device.screenHeight);

            if (!reportButton.isEmpty()) {
                AdbUtils::makeTap(m_account.deviceId, reportButton.x(), reportButton.y());
                QThread::msleep(1000);
            }

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

            Node reportTitle = xmlScreenParser.findTextNode("Выписка");
            if (!reportTitle.isEmpty() && reportTitle.y() < 300) {
                QDate beforeYesterday = DateUtils::getMoscowNow().date().addDays(-2);
                QString beforeYesterdayTitle = beforeYesterday.toString("dd.MM.yyyy");

                for (int i = 0; i < 5; ++i) {
                    Node byDayTitle = xmlScreenParser.findTextNode(beforeYesterdayTitle);
                    if (!byDayTitle.isEmpty()) {
                        qWarning() << "--- beforeYesterdayTitle found!";
                        break;
                    }
                    AdbUtils::makeSwipe(
                        m_account.deviceId,
                        device.screenWidth / 2, device.screenHeight / 4 * 3,
                        device.screenWidth / 2, device.screenHeight / 4
                    );
                    QThread::msleep(1000);
                    xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
                }
            } else {
                qWarning() << "--- reportTitle not found";
            }

            // все поддвержденные
            QList<TransactionInfo> parsedTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory();
            QSet<int> parsedTransactionIds;
            for (const TransactionInfo &transaction: parsedTransactions) {
                bool updated = false;

                for (const TransactionInfo &saved: localTransactions) {
                    if (parsedTransactionIds.contains(saved.id)) {
                        continue;
                    }
                    QDate sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy HH:mm:ss").date();
                    if (!sDate.isValid()) {
                        sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy").date();
                    }
                    QDate pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy HH:mm:ss").date();
                    if (!pDate.isValid()) {
                        pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy").date();
                    }
                    // Если сумма и дата совпадают
                    if (saved.amount == transaction.amount && sDate == pDate) {
                        if (transaction.description.startsWith("Перевод")) {
                            // Перевод по номеру
                            if (saved.bankName == transaction.bankName && saved.phone == transaction.phone) {
                                parsedTransactionIds.insert(saved.id);
                                updated = true;
                                if (saved.status != TransactionStatus::Complete || saved.description.isEmpty()) {
                                    if (!TransactionDAO::updateTransaction(
                                        saved.id,
                                        TransactionStatus::Complete,
                                        saved.description,
                                        transaction.description
                                    )) {
                                        qDebug().noquote().nospace() << "--- updated+phone failed" <<
                                                convertTransactionToString(transaction);;
                                    }
                                }
                                break;
                            }
                        } else {
                            // перевод по карте
                            // перезаписать  saved.description -> updatedDescription если не равны
                            if (!saved.description.isEmpty()) {
                                if (saved.description == transaction.description) {
                                    //  описания совпадают
                                    if (saved.status != TransactionStatus::Complete) {
                                        if (!TransactionDAO::updateTransaction(
                                            saved.id,
                                            TransactionStatus::Complete,
                                            saved.description,
                                            transaction.description
                                        )) {
                                            qDebug().noquote().nospace() << "--- updated+card[description same] failed"
                                                    <<
                                                    convertTransactionToString(transaction);;
                                        }
                                    }
                                    parsedTransactionIds.insert(saved.id);
                                    updated = true;
                                    break;
                                } else {
                                    // описания не совпадают, то пробуем найти такое же, если не находим то это новая
                                    bool findWithSameName = false;
                                    for (const TransactionInfo &saved2: localTransactions) {
                                        if (saved2.description == transaction.description && !parsedTransactionIds.
                                            contains(
                                                saved2.id)) {
                                            // мы нашли с одинаковым описанием и еще не обработанную
                                            if (saved2.status != TransactionStatus::Complete) {
                                                if (!TransactionDAO::updateTransaction(
                                                    saved2.id,
                                                    TransactionStatus::Complete,
                                                    saved2.description,
                                                    transaction.description
                                                )) {
                                                    qDebug().noquote().nospace() <<
                                                            "--- updated+card2[description same] failed"
                                                            <<
                                                            convertTransactionToString(transaction);;
                                                }
                                            }
                                            parsedTransactionIds.insert(saved2.id);
                                            updated = true;
                                            findWithSameName = true;
                                            break;
                                        }
                                    }
                                    if (!findWithSameName) {
                                        // обновляем описание
                                        if (!TransactionDAO::updateTransaction(
                                            saved.id,
                                            TransactionStatus::Complete,
                                            saved.description,
                                            transaction.description
                                        )) {
                                            qDebug().noquote().nospace() <<
                                                    "--- updated+card2+new desc[description same] failed" <<
                                                    convertTransactionToString(transaction);;
                                        }
                                    }
                                    parsedTransactionIds.insert(saved.id);
                                    updated = true;
                                    break;
                                }
                            } else {
                                // пустой описание
                                if (!TransactionDAO::updateTransaction(
                                    saved.id,
                                    TransactionStatus::Complete,
                                    saved.description,
                                    transaction.description
                                )) {
                                    qDebug().noquote().nospace() <<
                                            "--- updated+card[empty description]" <<
                                            convertTransactionToString(transaction);;
                                }
                                parsedTransactionIds.insert(saved.id);
                                updated = true;
                                break;
                            }
                        }
                    }
                }
                if (!updated) {
                    qDebug() << "--- insert: " << transaction.description;
                    if (!saveAndPostNewTransactionData(m_account, transaction)) {
                        qDebug() << "--- saveAndPostNewTransactionData failed";
                    }
                }

                // Если это перевод
                // Если совпадает по сумме + телефон + банк дата (без времени) + банк

                // Если по карте, мы знаем ток дату + сумма
            }
        }
    } else {
        qDebug() << "--- home screen not found";
    }
}
