#include <QApplication>
#include <QThread>

#include "dao/AccountDAO.h"
#include "views/MainWindow.h"

#include "database/DatabaseManager.h"
#include "database/dao/CommonDataDAO.h"
#include "db/AccountInfoScreener.h"
#include "services/DeviceScreener.h"

#include <iostream>
#include <QStyleFactory>
#include <thread>
#include <chrono>
#include <QFile>

#include "EventHandler.h"
#include "net/NetworkService.h"
#include "rshb/GetLastDaysHistoryScript.h"
#include "rshb/HomeScreenScript.h"
#include "rshb/PayByPhoneScript.h"

void startDeviceScreener(const QCoreApplication &app) {
    auto *thread = new QThread();
    auto *deviceScreenerWorker = new DeviceScreener;

    // Перемещаем worker в новый поток thread.
    // Это значит, что все слоты worker, вызываемые через connect(), теперь будут исполняться в этом фоне-потоке.
    deviceScreenerWorker->moveToThread(thread);

    // Когда поток запустится, автоматически вызовется worker->start() внутри фонового потока.
    QObject::connect(thread, &QThread::started, deviceScreenerWorker, &DeviceScreener::start);

    // 🔁 Эти 3 строки делают автоматическую зачистку:
    // Когда worker закончит работу (emit finished()), мы:
    // - останавливаем поток (thread->quit())
    // - удаляем worker (deleteLater)
    // - удаляем thread (deleteLater)
    // Это защищает от утечек памяти и оставшихся потоков после завершения.
    QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, thread, &QThread::quit);
    QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, deviceScreenerWorker, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);

    // Когда пользователь закрывает приложение (Ctrl+C, exit() и т.п.), мы вызываем worker->stop() — ты сам пишешь, что в этом методе.
    //Обычно он просто ставит флаг m_running = false, чтобы остановить бесконечный цикл в start()
    QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
        deviceScreenerWorker->stop();
    });

    thread->start();
}

void startEventHandler(const QCoreApplication &app) {
    auto *thread = new QThread;
    auto *eventHandler = new EventHandler;
    eventHandler->moveToThread(thread);
    QObject::connect(thread, &QThread::started, eventHandler, &EventHandler::start);
    QObject::connect(eventHandler, &EventHandler::finished, thread, &QThread::quit);
    QObject::connect(eventHandler, &EventHandler::finished, eventHandler, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
    QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
        eventHandler->stop();
    });
    thread->start();
}

void startNetworkService(const QCoreApplication &app) {
    auto *paymentThread = new QThread;
    auto *networkService = new NetworkService;
    networkService->moveToThread(paymentThread);
    QObject::connect(paymentThread, &QThread::started, networkService, &NetworkService::start);
    QObject::connect(networkService, &NetworkService::finished, paymentThread, &QThread::quit);
    QObject::connect(networkService, &NetworkService::finished, networkService, &QObject::deleteLater);
    QObject::connect(paymentThread, &QThread::finished, paymentThread, &QThread::deleteLater);
    QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
        networkService->stop();
    });
    paymentThread->start();
}

static QFile logFile;
static QMutex logMutex;

void messageHandler(
    const QtMsgType type,
    const QMessageLogContext &context,
    const QString &msg
) {
    Q_UNUSED(context) // можно раскомментировать, если нужны file/line/function
    // Формируем строку с типом и временем
    const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    QString level;
    switch (type) {
        case QtDebugMsg: level = "DEBUG";
            break;
        case QtInfoMsg: level = "INFO";
            break;
        case QtWarningMsg: level = "WARNING";
            break;
        case QtCriticalMsg: level = "CRITICAL";
            break;
        case QtFatalMsg: level = "FATAL";
            break;
    }


    const QString line = QString("%1 [%2] [%3:%4] %5\n")
            .arg(timestamp, level, context.function, QString::number(context.line), msg);
    // Записываем в файл (потокобезопасно)
    {
        QMutexLocker locker(&logMutex);
        if (logFile.isOpen()) {
            QTextStream(&logFile) << line;
            logFile.flush();
        }
    }

    // По желанию — дублировать в консоль
    const QByteArray localMsg = line.toLocal8Bit();
    fprintf(stderr, "%s", localMsg.constData());

    if (type == QtFatalMsg) {
        abort();
    }
}

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // Выбрать стиль Fusion
    QApplication::setStyle(QStyleFactory::create("Fusion"));

    logFile.setFileName("application.log");
    if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
        qWarning() << "Не удалось открыть лог-файл для записи";
    }
    // Устанавливаем свой обработчик
    qInstallMessageHandler(messageHandler);


    // 7927296033 - Амир
    // 79829976987 - Егор
    // 79641815146 - Мама Альфа
    // 79199196105 - Папа рсхб

    startNetworkService(app);
    startDeviceScreener(app);
    startEventHandler(app);

    MainWindow window;
    window.show();
    return QApplication::exec();
}
