/**
 * "UltimateDailyWallpaper" Copyright (C) 2026 Patrice Coni
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "mainwindow.h"

#include <QApplication>
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QMessageBox>
#include <QDebug>
#include <QDesktopServices>
#include <QProcess>
#include <QThread>
#include <QDate>
#if QT_VERSION >= 0x060000
    #include <QWidget>
#else
    #include <QDesktopWidget>
#endif
#include <QPluginLoader>
#include <QFileInfo>
#include <QtGlobal>
#include <QFileDialog>
#include <QScreen>

#ifdef Q_OS_MACOS
void MainWindow::ScreenLocked(CFNotificationCenterRef, void *observer, CFNotificationName, const void *, CFDictionaryRef)
{
    MainWindow *pMainWin = (MainWindow *)observer;
    pMainWin->_screenCurrentlyLocked = true;
}

void MainWindow::ScreenUnlocked(CFNotificationCenterRef, void *observer, CFNotificationName, const void *, CFDictionaryRef)
{
    MainWindow *pMainWin = (MainWindow *)observer;
    pMainWin->_screenCurrentlyLocked = false;
    if (pMainWin->_needsRefreshAfterUnlock)
    {
        pMainWin->_needsRefreshAfterUnlock = false;
        pMainWin->update_all();
    }
}
#endif

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      _screenCurrentlyLocked(false),
      _needsRefreshAfterUnlock(false)
{
    _AppFileDir       = QDir::homePath()+"/.UltimateDailyWallpaper";
    _databaseFilePath = _AppFileDir+"/udw_database.sqlite";
    _confFile         = _AppFileDir+"/settings.conf";
    _thumbfiledir     = _AppFileDir+"/thumbnails";

    QObject::connect(this, &MainWindow::_setWallpaper, [=](QString _wallpaperfile, int _set_Parameter, int _change_lockscreen_wallpaper)
    {
            setwall._set_wallpaper(_wallpaperfile, _set_Parameter, _change_lockscreen_wallpaper);
    });

    qApp->setAttribute(Qt::AA_DontShowIconsInMenus, false);
    qApp->setQuitOnLastWindowClosed(false);

    QDir _settDir(_AppFileDir);
    if(!_settDir.exists())
    {
        if(hasInternet())
        {
            _settDir.mkpath(_AppFileDir);
        }
        else
        {
            QMessageBox MsgError;
            MsgError.setIcon(QMessageBox::Critical);
            MsgError.setText(tr("No connection to the internet.\n"
                             "The application will be closed."));
            MsgError.setStandardButtons(QMessageBox::Ok);

            connect(MsgError.button(QMessageBox::Ok), &QPushButton::clicked, this, [=]()
            {
                exit(0);
            });

            MsgError.exec();
        }
    }

    QFile confFile(_confFile);
    if(!confFile.exists(_confFile))
    {
        QString langfilesdir;

#if defined(Q_OS_LINUX)
        plugdir=PLUGINS_DIR;

        QDir dir(plugdir);

        if (!dir.exists())
        {
            QMessageBox::StandardButton reply;
            reply = QMessageBox::question(0, tr("Reset"), tr("The folder containing the plugins was not found. "
                                                            "Do you want to set the folder manually?"),
                                            QMessageBox::Yes | QMessageBox::No);

            if (reply == QMessageBox::Yes) {
                // If the user clicks "Yes", open a file dialog to select the folder
                plugdir = QFileDialog::getExistingDirectory(this, tr("Select Plugin Folder"),
                                                            QDir::homePath(),
                                                            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
            }
        } else {
            // If the folder exists, check if *.so* files are present
            QFileInfoList soFiles = dir.entryInfoList(QStringList() << "*.so*", QDir::Files);

            if (soFiles.isEmpty()) {
                QMessageBox::warning(this, tr("No Plugins Found"),
                                    tr("The folder does not contain any plugin files (*.so). Please choose a valid plugin folder."));
            }
        }


        /* ****************************************************
         * Set the path where the translation files are stored
         * **************************************************** */

        langfilesdir=TR_PATH;

#elif defined(Q_OS_MACOS)
        plugdir=QApplication::applicationDirPath()+"/"+"plugins";
        langfilesdir=QApplication::applicationDirPath()+"/"+"locale";
#endif

        QString _defaultcontent =
                "[SETTINGS]\n"
                "pluginsdir="+plugdir+"\n"
                "langfilesdir="+langfilesdir+"\n"
                "picturedir="+_AppFileDir+"/picturefiles\n"
                "autorun=2\n"
                "store_days=15\n"
                "app_lang=en\n"
                "\n"
                "[SETWALLPAPER]\n"
                "autochange=2\n"
                "auto_timebased_change=1\n"
                "time_hours=18\n"
                "time_minutes=0\n"
                "change_lockscreen_wallpaper=2\n"
                "used_desktop=0\n"
                "last_change="+QDate::currentDate().toString("yyyyMMdd")+"\n"
                "last_file=0\n"
                "\n"
                "[PROVIDER_SETTINGS]\n"
                "selected_provider=0\n"
                "selected_plugin=0\n";

        if (confFile.open(QIODevice::Append))
        {
            QTextStream stream(&confFile);
            stream << _defaultcontent << Qt::endl;
        }
    }

#if defined(Q_OS_LINUX)
    QString _current_desktop=qgetenv("XDG_CURRENT_DESKTOP");

    if(_current_desktop=="Budgie:GNOME")
    {
        _used_desktop=0;
    }
    else if(_current_desktop=="X-Cinnamon" || _current_desktop.contains("Cinnamon"))
    {
        _used_desktop=1;
    }
    else if(_current_desktop=="LXDE")
    {
        _used_desktop=2;
    }
    else if(_current_desktop=="MATE")
    {
        _used_desktop=3;
    }
    else if(_current_desktop=="Trinity" || _current_desktop=="TDE")
    {
        _used_desktop=4;
    }
    else if(_current_desktop=="KDE")
    {
        QString kdefullsession=qgetenv("KDE_FULL_SESSION");
        QString kdeversion=qgetenv("KDE_SESSION_VERSION");

        if(kdefullsession=="true" && kdeversion=="5")
        {
            _used_desktop=5;
        } else if(kdefullsession=="true" && kdeversion=="6")
        {
            _used_desktop=9;
        }
    }
    else if(_current_desktop=="LXQt")
    {
        _used_desktop=6;
    }
    else if(_current_desktop=="Deepin")
    {
        _used_desktop=7;
    }
    else if(_current_desktop=="GNOME-Flashback" || _current_desktop=="GNOME-Classic:GNOME")
    {
        _used_desktop=8;
    }

    set_used_desktop(_used_desktop);

#elif defined(Q_OS_MACOS)
    _used_desktop=0;
#endif

    load_settings();

    translator=new QTranslator;

    QString _locale=QLocale::system().name();

    /* ***************************************************
     * Untranslated language files serve as placeholders.
     * ***************************************************/

    if(!(_applang==_locale))
    {
        _applang.clear();

        if(_locale.contains("de"))
        {
            _applang="de";
            change_applang(_applang);
        }
        else if (_locale.contains("fr"))
        {
            _applang="fr";
            change_applang(_applang);
        }
        else if (_locale.contains("it"))
        {
            _applang="it";
            change_applang(_applang);
        }
        else if (_locale.contains("es"))
        {
            _applang="es";
            change_applang(_applang);
        }
        else if (_locale.contains("fi"))
        {
            _applang="fi";
            change_applang(_applang);
        }
        else if (_locale.contains("ko"))
        {
            _applang="ko";
            change_applang(_applang);
        }
        else if (_locale.contains("ru"))
        {
            _applang="ru";
            change_applang(_applang);
        }
        else if (_locale.contains("uk"))
        {
            _applang="uk";
            change_applang(_applang);
        }
        else if (_locale.contains("pt"))
        {
            _applang="pt";
            change_applang(_applang);
        }
        else if (_locale.contains("ca"))
        {
            _applang="ca";
            change_applang(_applang);
        }
        else if (_locale.contains("en"))
        {
            _applang="en";
            change_applang(_applang);
        }
    }

    if (_applang != "en")
    {
        QString langfilename=QApplication::applicationName()+"_"+_applang;

        if (!translator->load(_langfilesdir + "/" + langfilename))
        {
            qDebug()<<_langfilesdir + "/" + langfilename;
            qWarning() << "Failed to load translation file:" << langfilename;
        }
        qApp->installTranslator(translator);
    }

    detectPlugins();

    if(detected_providers.isEmpty())
    {
        QMessageBox::critical(this, tr("Error"), tr("No plugins found."));
        exit(0);
    }

    if (loadPlugin(_selected_plugin))
    {
        qDebug().noquote()<<tr("done.");
        qDebug().noquote()<<tr("Used plugin: ")+_selected_plugin<<"/"<<basicinterface->pluginname();
    }
    else
    {
        QMessageBox::critical(this, tr("Error"), tr("Error while loading plugin."));
    }

    /* read variable $XDG_CONFIG_HOME.
     * If the variable is empty then set default directory $HOME/.config
     * If the variable contains more than one directory (e.g. PATH1:PATH2...)
     * then split by ":" and select the first directory as autostartDir. */

    QString _confDirVariable = qgetenv("XDG_CONFIG_HOME");
    QString _autorun_location;
    QStringList _detected_autorun_dirs;

    if(_confDirVariable.contains(":"))
    {
        _detected_autorun_dirs = _confDirVariable.split(":");
        _autorun_location = _detected_autorun_dirs.at(0)+"/autostart";
    } else {
        if(_confDirVariable.contains("/"))
        {
            _autorun_location = _confDirVariable.toUtf8()+"/autostart";
        } else {
            _autorun_location = QDir::homePath()+"/.config/autostart";
        }
    }

    QFile autorun_file;

#if defined(Q_OS_LINUX)
    QDir _autorundir(_autorun_location);
    if(!_autorundir.exists())
    {
        _autorundir.mkdir(_autorun_location);
    }
    autorun_file.setFileName(_autorun_location+"/"+QApplication::applicationName()+".desktop");
#elif defined(Q_OS_MACOS)
    autorun_file.setFileName(QDir::homePath()+"/Library/LaunchAgents/"+"com.yourcompany."+QApplication::applicationName()+".plist");
#endif

    if(_autorun==2)
    {
        if(!autorun_file.exists())
        {
#if defined(Q_OS_LINUX)
            QString install_path=INSTALLATION_PATH; // Path of the Installation
            QString bin_path=BINDIR_PATH;           // BIN_DIR

            QString _autorun_file_content =
                "[Desktop Entry]\n"
                "Type=Application\n"
                "Exec="+bin_path+"/"+QApplication::applicationName()+"\n"
                "Hidden=false\n"
                "Name="+QApplication::applicationName()+"\n"
                "Terminal=false\n"
                "Icon="+install_path+"/ultimatedesktopwallpaper_icon.png";
#elif defined(Q_OS_MACOS)
            QString _autorun_file_content =
                "<?xml version=\"+APP_VERSION+\" encoding=\"UTF-8\"?>\n"
                "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
                "<plist version=\"+APP_VERSION+\">\n"
                "<dict>\n"
                "<key>ProgramArguments</key>\n"
                "<array>\n"
                "<string>"+QApplication::applicationFilePath()+"</string>\n"
                "</array>\n"
                "<key>RunAtLoad</key>\n"
                "<true/>\n"
                "<key>Label</key>\n"
                "<string>"+QApplication::applicationName()+"</string>\n"
                "</dict>\n"
                "</plist>\n";
#endif
            if (autorun_file.open(QIODevice::Append))
            {
                QTextStream stream(&autorun_file);
                stream <<_autorun_file_content<<Qt::endl;
            }
        }
    }
    else
    {
        if(autorun_file.exists())
        {
            autorun_file.remove();
        }
    }

    if(createConnection()==false)
    {
        QMessageBox MsgError;
        MsgError.setIcon(QMessageBox::Critical);
        MsgError.setText(tr("An error was detected when starting the application.\n"
                            "The application will be closed."));
        MsgError.setStandardButtons(QMessageBox::Ok);

        connect(MsgError.button(QMessageBox::Ok), &QPushButton::clicked, this, [=]()
        {
            exit(0);
        });

        MsgError.exec();
    }

    mSystemTrayIcon = new QSystemTrayIcon(this);

    regular_request=true;
    startseq=true;
    request_dl_wallpaper();

    if(!(_last_file=="0") && !(_last_file.isEmpty()))
    {
        /* If the last_file from config file not found
         * then load last_record */

        if(get_record("filename", _last_file, "", false)==false)
        {
            get_record("", "", _selected_provider, true);
        }
    } else
    {
        get_record("", "", _selected_provider, true);
    }

    if(_record_out.last().isEmpty())
    {
        create_MenuHead(_record_out.at(0), _record_out.at(1), _record_out.at(4));
    } else
    {
        create_MenuHead(_record_out.at(0)+" - "+_record_out.last(), _record_out.at(1), _record_out.at(4));
    }

    create_Actions();
    create_Menu();

    if(_autochange==2)
    {
        no_autochange();
        set_autochange();

        if(same_date()==true)
        {
            load_wallpaper();
        } else
        {
            if(hasInternet())
            {
                update_all();
            } else
            {
                load_wallpaper();
            }
        }
    }
    else
    {
        no_autochange();
    }

    if(!hasInternet())
    {
        _display_tooltip(tr("No connection to the internet."), tr("Please check your internet connection."));
    }
    else
    {
        _display_tooltip(_record_out.at(1), _record_out.at(0));
    }

    set_SystemTrayIcon();

    connect(mSystemTrayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(slotActive(QSystemTrayIcon::ActivationReason)));

    check_content();
}

MainWindow::~MainWindow()
{
}

void MainWindow::slotActive(QSystemTrayIcon::ActivationReason r)
{
#if QT_VERSION >= 0x060000
    if (r == QSystemTrayIcon::Trigger)
    {
        QPoint cursorPos = QCursor::pos();

        QScreen *screen = QGuiApplication::screenAt(cursorPos);

        if (screen)
        {
            QRect screenGeometry = screen->geometry();

            QRect trayIconGeometry = mSystemTrayIcon->geometry();
            Q_UNUSED(trayIconGeometry);

            QPoint menuPos = cursorPos;

            int menuWidth = basemenu->sizeHint().width();
            int menuHeight = basemenu->sizeHint().height();

            if (cursorPos.y() + menuHeight > screenGeometry.bottom())
            {
                menuPos.setY(cursorPos.y() - menuHeight);
            }

            if (cursorPos.x() + menuWidth > screenGeometry.right())
            {

                menuPos.setX(screenGeometry.right() - menuWidth);
            }
            else if (cursorPos.x() < screenGeometry.left())
            {

                menuPos.setX(screenGeometry.left());
            }
            basemenu->popup(menuPos);
        }
    }
#else
    if (r == QSystemTrayIcon::Trigger)
    {
        basemenu->exec(QCursor::pos());
    }
#endif
}

void MainWindow::set_autochange()
{
    if (_autochange==2 && _autoChangeTimer == NULL)
    {
        QTime scheduledTime(_time_hours, _time_minutes);

        // Default of midnight if time is invalid for some reason...
        if (!scheduledTime.isValid())
        {
            scheduledTime.setHMS(23,59,59);
        }

        int milliSecondsToGo = QTime::currentTime().msecsTo(scheduledTime);

        // If time is in the past, schedule it for tomorrow...
        if (milliSecondsToGo < 0)
        {
            // 0,0 is the start of the day whereas 23,59 + 1 min is tonight at midnight...
            int msUntilMidnight = QTime::currentTime().msecsTo(QTime(23,59)) + 60000;
            milliSecondsToGo = msUntilMidnight + (QTime(0,0).msecsTo(scheduledTime));
        }

        // Some padding for good measure to avoid firing more than once at the scheduled time
        milliSecondsToGo += 3000;

        _autoChangeTimer = new QTimer(QCoreApplication::instance());

        conn = QObject::connect(_autoChangeTimer, &QTimer::timeout, [this]()
        {
            update_all();
            check_content();

            // reset timer to avoid firing more than once.

            _autoChangeTimer->stop();
            _autoChangeTimer->deleteLater();

            _time_hours=0;
            _time_minutes=0;

            load_settings();

            no_autochange();
            set_autochange();
        });

        _autoChangeTimer->start(milliSecondsToGo);
    }
}

void MainWindow::check_content()
{
    if(get_date_list()==true)
    {
        delete_old_pictures();
    }
}

void MainWindow::no_autochange()
{
    if (_autoChangeTimer != NULL)
    {
        _autoChangeTimer->stop();
        QObject::disconnect(conn);
        delete _autoChangeTimer;
        _autoChangeTimer = NULL;
    }
}

void MainWindow::load_settings()
{
    QSettings settings(_confFile, QSettings::IniFormat);

    settings.beginGroup("SETTINGS");
    _langfilesdir = settings.value("langfilesdir","").toString();
    _pluginsdir = settings.value("pluginsdir","").toString();
    _picturedir = settings.value("picturedir","").toString();
    _autorun = settings.value("autorun","").toInt();
    _store_days = settings.value("store_days","").toInt();
    _applang = settings.value("app_lang","").toString();
    settings.endGroup();

    settings.beginGroup("SETWALLPAPER");
    _autochange = settings.value("autochange","").toInt();
    _time_hours = settings.value("time_hours","").toInt();
    _time_minutes = settings.value("time_minutes","").toInt();
    _change_lockscreen_wallpaper = settings.value("change_lockscreen_wallpaper","").toInt();
    _last_change = settings.value("last_change","").toString();
    _last_file = settings.value("last_file","").toString();
    settings.endGroup();

    settings.beginGroup("PROVIDER_SETTINGS");
    _selected_provider = settings.value("selected_provider","").toString();
    _selected_plugin = settings.value("selected_plugin","").toString();
    _lang = settings.value("lang","").toString();
    settings.endGroup();
}

void MainWindow::request_dl_wallpaper()
{
    if(hasInternet())
    {
        basicinterface->get_picture(false, _picturedir, _applang, 0, 0, 0);
        if(regular_request==false)
        {
            if(same_date()==false)
            {
                update_all();
            }
            if(startseq==true)
            {
                if(same_date()==false)
                {
                    update_all();
                }
                startseq=false;
            }
        }
        if(startseq==true)
        {
            startseq=false;

            // Retry every 5 seconds until the internet is available (max. 5 minutes in total)
            static int retryCount = 0;
            const int maxRetries = 60;  // 60 retries = max. 5 minutes (300 seconds)

            if (retryCount < maxRetries)
            {
                retryCount++;
                qDebug() << "[NET] Internet unavailable, retrying... Attempt:" << retryCount;
                QTimer::singleShot(5000, this, &MainWindow::request_dl_wallpaper);  // Retry after 5 seconds
            }
            else
            {
                qDebug() << "[NET] Maximum retry limit reached. Download failed.";
                retryCount = 0;  // Reset retry count for the next session
            }
        }
    }
    else
    {
        regular_request=false;
        QTimer::singleShot(5000, this, &MainWindow::request_dl_wallpaper);        
    }
}

void MainWindow::create_MenuHead(QString description, QString title, QString thumbfile)
{
    _descWidget = new QWidget();
    dL = new QVBoxLayout();
    _imageLabel = new QLabel();
    _labelTitle = new QLabel();
    _labelDescription = new QLabel();

    _labelTitle->setText(title);
    _labelDescription->setText(description);

    _imageLabel->setAlignment(Qt::AlignCenter);
    _labelTitle->setAlignment(Qt::AlignCenter);
    _labelDescription->setAlignment(Qt::AlignCenter);

    _headImage.load(_thumbfiledir+"/"+thumbfile);
    _descImage = _headImage.scaled(280,170, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    _imageLabel->setPixmap(QPixmap::fromImage(_descImage));

    _labelDescription->setWordWrap(true);

#if defined(Q_OS_LINUX)
    _labelDescription->setStyleSheet("font: 8pt; font-style: italic; text-align:center");
    _labelTitle->setStyleSheet("font: 8pt; font-weight: bold; text-align:center;");
#elif defined(Q_OS_MACOS)
    _labelDescription->setStyleSheet("font: 11pt; font-style: italic; text-align:center");
    _labelTitle->setStyleSheet("font: 11pt; font-weight: bold; text-align:center;");
#endif

    dL->addWidget(_labelTitle);
    dL->addWidget(_imageLabel);
    dL->addWidget(_labelDescription);
    _descWidget->setLayout(dL);
    _descWidget->show();
}

void MainWindow::create_Menu()
{
    basemenu  = new QMenu(this);
    provider  = new QMenu(this);

    _widgetaction = new QWidgetAction(basemenu);
    _widgetaction->setDefaultWidget(_descWidget);

    basemenu->addAction(_widgetaction);
    basemenu->addSeparator();

    // basemenu->addAction(getnewpicture);

    basemenu->addAction(moreinformation);

    if(_selected_provider=="Wikimedia Commons")
    {
        basemenu->addAction(wmc_potd_morepictures);
    }

    if(basicinterface->SetMenuInterface()==true)
    {
        for(int i=0;i<menuinterface->MenuTriggers().size();i++)
        {
            auto action = new QAction(menuinterface->MenuTriggers().at(i), this);
            connect(action, &QAction::triggered, [=]()
            {
                extendedfunctioninterface->ExtendedFunction1();
                // do something;
            });

            basemenu->addAction(action);
        }
    }

    if(basicinterface->SetSubMenuInterface()==true)
    {
        auto menu = new QMenu;
        menu=basemenu->addMenu(submenuinterface->SubMenuTitle());
        for(int i=0;i<submenuinterface->SubMenuTriggers().size();i++)
        {
            auto action = new QAction(submenuinterface->SubMenuTriggers().at(i), this);
            connect(action, &QAction::triggered, [=]()
            {
                submenuinterface->SubMenuFunction(submenuinterface->SubMenuEmitStrings().at(i));
                load_settings();
                update_all();
            });
            menu->addAction(action);
        }
    }

    basemenu->addSeparator();
    basemenu->addAction(loadexistingpicture);
    basemenu->addSeparator();

    provider = basemenu->addMenu(tr("&Provider"));
    for(int i=0; i<detected_providers.size();i++)
    {
        auto action = new QAction(detected_providers.at(i), this);
        connect(action, &QAction::triggered, [=]()
        {
            emit(change_provider(detected_providers.at(i), detected_plugins.at(i)));
            load_settings();
            if (loadPlugin(_selected_plugin))
            {
                qDebug().noquote()<<tr("done.");
                qDebug().noquote()<<tr("Used plugin: ")+_selected_plugin<<"/"<<basicinterface->pluginname();
            }
            else
            {
                QMessageBox::critical(this, tr("Error"), tr("Error while loading plugin."));
            }
            update_all();
        });

        provider->addAction(action);
    }

    basemenu->addAction(settings);
    basemenu->addAction(aboutapp);
    basemenu->addSeparator();
    basemenu->addAction(quitapp);
}

void MainWindow::create_Actions()
{
    /*
    getnewpicture = new QAction(tr("&Get new picture"), this);
    connect(getnewpicture, &QAction::triggered, this, &MainWindow::mnu_getnewpicture);
    */

    if(_selected_provider=="Wikimedia Commons")
    {
        moreinformation = new QAction(tr("&About this picture and license"), this);
    }
    else
    {
        moreinformation = new QAction(tr("&About this picture and copyright"), this);
    }

    connect(moreinformation, &QAction::triggered, this, &MainWindow::mnu_moreinformation);

    if(_selected_provider=="Wikimedia Commons")
    {
        wmc_potd_morepictures = new QAction(tr("&Download past pictures"), this);
        connect(wmc_potd_morepictures, &QAction::triggered, this, &MainWindow::wikimedia_commons_more_pictures);
    }

    loadexistingpicture = new QAction(tr("&Load stored picture"), this);
    connect(loadexistingpicture, &QAction::triggered, this, &MainWindow::basemnu_loadexistingpicture);

    settings = new QAction(tr("&Settings"), this);
    connect(settings, &QAction::triggered, this, &MainWindow::basemnu_settings);

    aboutapp = new QAction(tr("&About"), this);
    connect(aboutapp, &QAction::triggered, this, &MainWindow::basemnu_aboutapp);

    quitapp = new QAction(tr("&Quit"), this);
    connect(quitapp, &QAction::triggered, qApp, &QCoreApplication::quit);
}

void MainWindow::wikimedia_commons_more_pictures()
{
    if (hasInternet())
    {
        show_photobrowser(1);
    }
    else
    {
        QApplication::setQuitOnLastWindowClosed(false);
        QMessageBox MsgError;
        MsgError.setIcon(QMessageBox::Warning);
        MsgError.setText(tr("No internet connection."));
        MsgError.exec();
    }
}

void MainWindow::mnu_getnewpicture()
{
    regular_request=true;
    request_dl_wallpaper();
    get_record("", "", _selected_provider, true);
    update_menu();
}

void MainWindow::mnu_moreinformation()
{
    QDesktopServices::openUrl(_record_out.at(7));
}

void MainWindow::basemnu_loadexistingpicture()
{
    if(get_date_list()==true)
    {
        delete_old_pictures();
    }

    show_photobrowser(0);
}

void MainWindow::basemnu_settings()
{
    SettingsWindow _sett_win;
    _sett_win.adjustSize();
    _sett_win.setModal(true);
    _sett_win.exec();
}

void MainWindow::basemnu_aboutapp()
{
    About _about_win;
    _about_win.adjustSize();
    _about_win.setMinimumSize(535,500);
    _about_win.set_plugin_text(basicinterface->plugininfo());
    _about_win.setModal(true);
    _about_win.exec();
}

void MainWindow::set_SystemTrayIcon()
{
    mSystemTrayIcon->setIcon(QIcon(":/icons/ultimatedesktopwallpaper_icon.png"));
    mSystemTrayIcon->show();
    mSystemTrayIcon->setVisible(true);
}

void MainWindow::_display_tooltip(QString _tooltip_title, QString _tooltip_message)
{
    if(!_tooltip_message.isEmpty())
    {
        QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(QSystemTrayIcon::Information);
        mSystemTrayIcon->showMessage(_tooltip_title, _tooltip_message, icon, 5000);
        mSystemTrayIcon->setToolTip(tr("Description: \n")+_tooltip_message);
    }
}

void MainWindow::change_date()
{
    QSettings _select_provider_settings(_confFile, QSettings::IniFormat);

    _select_provider_settings.beginGroup("SETWALLPAPER");
    _select_provider_settings.setValue("last_change", QDate::currentDate().toString("yyyyMMdd"));
    _select_provider_settings.endGroup();
    _select_provider_settings.sync();
}

void MainWindow::change_filename(QString filename)
{
    QSettings _select_provider_settings(_confFile, QSettings::IniFormat);

    _select_provider_settings.beginGroup("SETWALLPAPER");
    _select_provider_settings.setValue("last_file", filename);
    _select_provider_settings.endGroup();
    _select_provider_settings.sync();
}

void MainWindow::change_provider(QString _selected_provider, QString _plugin)
{
    QSettings _select_provider_settings(_confFile, QSettings::IniFormat);

    _select_provider_settings.beginGroup("PROVIDER_SETTINGS");
    _select_provider_settings.setValue("selected_provider", _selected_provider);
    _select_provider_settings.setValue("selected_plugin", _plugin);
    _select_provider_settings.endGroup();
    _select_provider_settings.sync();
}

void MainWindow::change_applang(QString _lang)
{
    QSettings _select_provider_settings(_confFile, QSettings::IniFormat);

    _select_provider_settings.beginGroup("SETTINGS");
    _select_provider_settings.setValue("app_lang", _lang);
    _select_provider_settings.endGroup();
    _select_provider_settings.sync();
}

void MainWindow::set_used_desktop(int parameter)
{
    QSettings _select_provider_settings(_confFile, QSettings::IniFormat);

    _select_provider_settings.beginGroup("SETWALLPAPER");
    _select_provider_settings.setValue("used_desktop", parameter);
    _select_provider_settings.endGroup();
    _select_provider_settings.sync();
}

bool MainWindow::get_record(QString where, QString content, QString provider, bool _get_last_record)
{
    QSqlDatabase udw_db;
    QSqlQuery udw_query(udw_db);

    if(QSqlDatabase::contains("qt_sql_default_connection"))
    {
        udw_db = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        udw_db = QSqlDatabase::addDatabase("QSQLITE");
    }

    udw_db.setDatabaseName(_databaseFilePath);
    udw_db.open();

    QStringList _basiccommandlist={"SELECT description FROM udw_history WHERE",
                                   "SELECT title FROM udw_history WHERE",
                                   "SELECT provider FROM udw_history WHERE",
                                   "SELECT filename FROM udw_history WHERE",
                                   "SELECT thumb_filename FROM udw_history WHERE",
                                   "SELECT size_width FROM udw_history WHERE",
                                   "SELECT size_height FROM udw_history WHERE",
                                   "SELECT browser_url FROM udw_history WHERE",
                                   "SELECT copyright FROM udw_history WHERE"
                                  };

    _record_out.clear();

    for(int i=0; i<_basiccommandlist.size();i++)
    {
        QString sqlcommand;

        if(_get_last_record==false)
        {
            sqlcommand.append(_basiccommandlist.at(i)+" "+where+"=\x27"+content+"\x27");
        } else
        {
            sqlcommand.append(_basiccommandlist.at(i)+" "+"provider=\x27"+provider+"\x27");
        }

        if(udw_query.exec(sqlcommand))
        {
            while(udw_query.next())
            {
                if(udw_query.last())
                {
                    _record_out.append(udw_query.value(0).toString());
                }
            }
        } else
        {
            qDebug() << udw_query.lastError().text();

            return false;
        }
    }    

    if(_record_out.isEmpty())
    {
        return false;
    }

    return true;
}

void MainWindow::load_wallpaper()
{
    if(_autochange==2)
    {
        emit _setWallpaper(_picturedir+"/"+_record_out.at(3), _used_desktop, _change_lockscreen_wallpaper);
        change_filename(_record_out.at(3));
    }
}

bool MainWindow::get_date_list()
{
    QSqlDatabase udw_db;
    QSqlQuery udw_query(udw_db);

    if(QSqlDatabase::contains("qt_sql_default_connection"))
    {
        udw_db = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        udw_db = QSqlDatabase::addDatabase("QSQLITE");
    }

    udw_db.setDatabaseName(_databaseFilePath);
    if (!udw_db.open())
    {
        return false;
    }

    udw_query.exec("SELECT date FROM udw_history");
    QSqlRecord record_date = udw_query.record();
    while (udw_query.next())
    {
        datelist.append(udw_query.value(record_date.indexOf("date")).toString());
    }
    udw_query.finish();
    udw_query.clear();

    return true;
}

bool MainWindow::create_filenamelist()
{
    QSqlDatabase udw_db;
    QSqlQuery udw_query(udw_db);

    if(QSqlDatabase::contains("qt_sql_default_connection"))
    {
        udw_db = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        udw_db = QSqlDatabase::addDatabase("QSQLITE");
    }

    udw_db.setDatabaseName(_databaseFilePath);
    if (!udw_db.open())
    {
        return false;
    }

    for(int i = 0; i < selected_datelist.size(); i++)
    {
        udw_query.prepare("SELECT filename FROM udw_history WHERE date=\x27"+selected_datelist.at(i).toUtf8()+"\x27");
        if(udw_query.exec() && udw_query.next())
        {
           if(!filenamelist.contains(udw_query.value(0).toString().toUtf8()))
           {
               filenamelist.append(udw_query.value(0).toString().toUtf8());
           }

           //Check if more entries with the same date and add it.
           while(udw_query.next()){
               if(!filenamelist.contains(udw_query.value(0).toString().toUtf8()))
               {
                   filenamelist.append(udw_query.value(0).toString().toUtf8());
               }
           }
        }

        udw_query.prepare("SELECT thumb_filename FROM udw_history WHERE date=\x27"+selected_datelist.at(i).toUtf8()+"\x27");
        if(udw_query.exec() && udw_query.next())
        {
           if(!_oldthumbfiles.contains(udw_query.value(0).toString().toUtf8()))
           {
               _oldthumbfiles.append(udw_query.value(0).toString().toUtf8());
           }

           //Check if more entries with the same date and add it.
           while(udw_query.next()){
               if(!_oldthumbfiles.contains(udw_query.value(0).toString().toUtf8()))
               {
                   _oldthumbfiles.append(udw_query.value(0).toString().toUtf8());
               }
           }
        }
    }

    udw_query.finish();
    udw_query.clear();

    return true;
}

void MainWindow::delete_old_records()
{
    QSqlDatabase udw_db;
    QSqlQuery udw_query(udw_db);

    if(QSqlDatabase::contains("qt_sql_default_connection"))
    {
        udw_db = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        udw_db = QSqlDatabase::addDatabase("QSQLITE");
    }

    udw_db.setDatabaseName(_databaseFilePath);

    for(int i = 0; i < selected_datelist.size(); i++)
    {
        udw_query.prepare("DELETE FROM udw_history WHERE date = \x27"+selected_datelist.at(i).toUtf8()+"\x27");
        if(!udw_query.exec())
        {
            qDebug() << udw_query.lastError();
        }
    }
    udw_query.finish();
    udw_query.clear();
}

void MainWindow::delete_old_pictures()
{
    for(int i = 0; i < datelist.size(); i++)
    {
        QDate current_date = QDate::currentDate();
        QDate selected_date = QDate::fromString(datelist.at(i), "yyyyMMdd");
        if(selected_date.daysTo(current_date)>_store_days) {
            selected_datelist.append(datelist.at(i));
        }
    }

    if(create_filenamelist()==true)
    {
        for(int j = 0; j < filenamelist.size(); j++)
        {
            QString oldwallfile = _picturedir+"/"+filenamelist.at(j);

            if(oldwallfile.contains("\x2F\x2F"))
            {
                oldwallfile.replace("\x2F\x2F", "\x2F");
            }

            QFile old_wallp(oldwallfile);
            if(old_wallp.exists())
            {
                old_wallp.remove();
            }
            qDebug() << "Picture " << oldwallfile << " deleted.";
            oldwallfile.clear();

            QString oldthumbfile = _thumbfiledir+"/"+_oldthumbfiles.at(j);

            if(oldthumbfile.contains("\x2F\x2F"))
            {
                oldthumbfile.replace("\x2F\x2F", "\x2F");
            }

            QFile old_thumbf(oldthumbfile);
            if(old_thumbf.exists())
            {
                old_thumbf.remove();
            }
            qDebug() << "Thumbnail-Picture " << oldthumbfile << " deleted.";
            oldthumbfile.clear();
        }
        delete_old_records();
    }
}

void MainWindow::update_menu()
{
    basemenu->clear();

    if(_record_out.last().isEmpty())
    {
        create_MenuHead(_record_out.at(0), _record_out.at(1), _record_out.at(4));
    } else
    {
        create_MenuHead(_record_out.at(0)+" - "+_record_out.last(), _record_out.at(1), _record_out.at(4));
    }

    create_Actions();
    create_Menu();
}

void MainWindow::update_all()
{
    if (!hasInternet())
    {
        _display_tooltip(
            tr("Offline"),
            tr("No internet connection available.")
        );
        return;
    }

    regular_request = true;
    request_dl_wallpaper();
    get_record("", "", _selected_provider, true);
    update_menu();

    if (_autochange == 2)
        load_wallpaper();

    _display_tooltip(_record_out.at(1), _record_out.at(0));

    if (!same_date())
        change_date();
}

void MainWindow::show_photobrowser(int mode)
{
    /* *****************************************************
     * mode variants
     * *****************************************************
     *
     *  0: Show stored pictures
     *
     *  1: Download Wikimedia Commons pictures of the day
     *     of past days within a given time range
     *
     * *****************************************************
     */

    PhotoBrowser _photobrowser;
    _photobrowser.adjustSize();
    _photobrowser.init(mode);
    _photobrowser.setModal(true);
    _photobrowser.exec();

    mSystemTrayIcon->setToolTip("");

    if (_photobrowser.wallchanged==true)
    {
       _photobrowser.wallchanged=false;

       _record_out.clear();

       _record_out << _photobrowser._pb_copyright_description_photo <<
                     _photobrowser._pb_headline <<
                     "0" <<
                     _photobrowser._photobrowser_specific_wallpaperfilename <<
                     _photobrowser._thumb_filename <<
                     "0" <<
                     "0" <<
                     _photobrowser._pb_copyright_link <<
                     _photobrowser._pb_copyright;

       change_filename(_record_out.at(3));
       update_menu();
    }
}

void MainWindow::_add_record(QString _description,
                             QString _copyright,
                             QString _provider,
                             QString _title_headline,
                             QString _filename,
                             QString _browser_url,
                             QString _thumb_filename,
                             int _size_height,
                             int _size_width,
                             int pageid,
                             bool tempdatabase,
                             QString potd_date)
{
    // =======================================
    // 0. Validate required fields
    // =======================================
    if (_provider.isEmpty() ||
        _title_headline.isEmpty() ||
        _filename.isEmpty() ||
        _thumb_filename.isEmpty() ||
        _browser_url.isEmpty() ||
        _size_height <= 0 ||
        _size_width <= 0)
    {
        qWarning() << "[DB] Invalid record skipped:"
                   << "provider=" << _provider
                   << "title=" << _title_headline
                   << "filename=" << _filename
                   << "size=" << _size_width << "x" << _size_height;
        return;
    }

    // =======================================
    // 1. Create a thread-local DB connection
    // =======================================
    QString connectionName =
        QString("udw_conn_%1")
        .arg(reinterpret_cast<quintptr>(QThread::currentThread()));

    // Use a local scope to ensure the database is destroyed before removeDatabase()
    {
        QSqlDatabase udw_db = QSqlDatabase::addDatabase("QSQLITE", connectionName);

        QString dbPath;
        if (tempdatabase)
            dbPath = _AppFileDir+"/temp/temp_udw_database.sqlite";
        else
            dbPath = _databaseFilePath;

        udw_db.setDatabaseName(dbPath);

        // Attempt to open the database
        if (!udw_db.open()) {
            qCritical() << "[DB] Cannot open database:" << udw_db.lastError();
            QSqlDatabase::removeDatabase(connectionName);
            return;
        }

        // =======================================
        // 2. Start transaction
        // =======================================
        if (!udw_db.transaction()) {
            qCritical() << "[DB] Cannot start transaction:" << udw_db.lastError();
            udw_db.close();
            QSqlDatabase::removeDatabase(connectionName);
            return;
        }

        // =======================================
        // 3. Prepare query
        // =======================================
        QSqlQuery udw_query(udw_db);

        if (tempdatabase)
        {
            udw_query.prepare(
                "INSERT INTO udw_history "
                "(id, date, description, copyright, title, provider, filename, "
                "browser_url, size_width, size_height, thumb_filename, pageid, potd_date) "
                "VALUES "
                "(:id, :date, :description, :copyright, :title, :provider, :filename, "
                ":browser_url, :size_width, :size_height, :thumb_filename, :pageid, :potd_date)"
            );
        }
        else
        {
            udw_query.prepare(
                "INSERT INTO udw_history "
                "(id, date, description, copyright, title, provider, filename, "
                "browser_url, size_width, size_height, thumb_filename, pageid) "
                "VALUES "
                "(:id, :date, :description, :copyright, :title, :provider, :filename, "
                ":browser_url, :size_width, :size_height, :thumb_filename, :pageid)"
            );
        }

        // =======================================
        // 4. Bind values
        // =======================================
        udw_query.bindValue(":id", QDateTime::currentDateTimeUtc().toString("yyyyMMddHHmmsszzz"));
        udw_query.bindValue(":date", QDate::currentDate().toString("yyyyMMdd"));
        udw_query.bindValue(":description", _description);
        udw_query.bindValue(":copyright", _copyright);
        udw_query.bindValue(":title", _title_headline);
        udw_query.bindValue(":provider", _provider);
        udw_query.bindValue(":filename", _filename);
        udw_query.bindValue(":browser_url", _browser_url);
        udw_query.bindValue(":size_width", _size_width);
        udw_query.bindValue(":size_height", _size_height);
        udw_query.bindValue(":thumb_filename", _thumb_filename);
        udw_query.bindValue(":pageid", pageid);

        if (tempdatabase)
            udw_query.bindValue(":potd_date", potd_date);

        // =======================================
        // 5. Execute insert
        // =======================================
        if (!udw_query.exec()) {
            qCritical() << "[DB] INSERT failed:" << udw_query.lastError();
            udw_db.rollback();
            udw_db.close();
            QSqlDatabase::removeDatabase(connectionName);
            return;
        }

        // =======================================
        // 6. Commit transaction
        // =======================================
        if (!udw_db.commit()) {
            qCritical() << "[DB] Commit failed:" << udw_db.lastError();
            udw_db.rollback();
        }

        // =======================================
        // 7. Cleanup
        // =======================================
        udw_query.finish();
        udw_db.close();
    } // QSqlDatabase destroyed here

    // Remove the connection after destruction to avoid Qt warnings
    QSqlDatabase::removeDatabase(connectionName);

    qDebug() << "[DB] Record inserted:" << _provider << "-" << _filename;
}

void MainWindow::detectPlugins()
{
    QDir pluginsDir(_pluginsdir);

    const QStringList entries = pluginsDir.entryList(QDir::Files);
    for (const QString &fileName : entries) {
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = pluginLoader.instance();
        if (plugin) {
            BasicInterface * bi;
            bi = qobject_cast<BasicInterface *>(plugin);
            if (bi)
            {
                detected_providers.append(bi->provider());
                detected_plugins.append(fileName);
            }
        }
        else
        {
            qDebug()<<pluginLoader.errorString();
        }
    }
}

bool MainWindow::loadPlugin(QString _pluginfilename)
{
    QDir pluginsDir(_pluginsdir);

    QPluginLoader pluginLoader;

    if(_pluginfilename=="0")
    {
        _pluginfilename.clear();
        _pluginfilename.append(detected_plugins.at(0));
        _selected_plugin.clear();
        _selected_plugin.append(detected_plugins.at(0));
        _selected_provider.clear();
        _selected_provider.append(detected_providers.at(0));
        change_provider(detected_providers.at(0), detected_plugins.at(0));
    }

    if(QFileInfo::exists(_pluginsdir+"/"+_pluginfilename))
    {
        pluginLoader.setFileName(_pluginsdir+"/"+_pluginfilename);
    }
    else
    {
        detectPlugins();
        change_provider(detected_providers.at(0), detected_plugins.at(0));
        pluginLoader.setFileName(_pluginsdir+"/"+detected_plugins.at(0));
    }

    qDebug().noquote()<<tr("Load plugin...");

    QObject *plugin = pluginLoader.instance();
    if (plugin)
    {
        basicinterface = qobject_cast<BasicInterface *>(plugin);

        if(basicinterface->SetSubMenuInterface()==true)
        {
            submenuinterface = qobject_cast<SubMenuInterface *>(plugin);
        }

        if(basicinterface->SetExtendedFunctionInterface()==true)
        {
            extendedfunctioninterface = qobject_cast<ExtendedFunctionInterface *>(plugin);
        }

        if(basicinterface->SetAdditionalFunctionInterface()==true)
        {
            additionalfunctioninterface = qobject_cast<AdditionalFunctionInterface *>(plugin);
        }

        if(basicinterface->SetMenuInterface()==true)
        {
            menuinterface = qobject_cast<MenuInterface *>(plugin);
        }

        if (basicinterface)
        {
            connect(plugin, SIGNAL(download_successful(QString, QString, QString,
                                                      QString, QString,
                                                      QString, QString,
                                                      int, int, int,
                                                      bool, QString)),
                    this, SLOT(_add_record(QString, QString, QString,
                                     QString, QString,
                                     QString, QString,
                                     int, int, int,
                                     bool, QString)));

            return true;
        }
        pluginLoader.unload();
    }
    return false;
}

bool MainWindow::same_date()
{
    _last_change.clear();
    load_settings();
    QString current_date=QDate::currentDate().toString("yyyyMMdd");
    if(_last_change==current_date)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool MainWindow::hasInternet()
{
    QDateTime now = QDateTime::currentDateTime();

    if (!_lastInternetCheck.isValid() ||
        _lastInternetCheck.secsTo(now) >= _internetCheckIntervalSec)
    {
        _isOnline = check_internet_connection();
        _lastInternetCheck = now;

        qDebug() << "[NET] Internet rechecked:" << _isOnline;
    }
    else
    {
        qDebug() << "[NET] Cached internet state used:" << _isOnline;
    }

    return _isOnline;
}

bool MainWindow::check_internet_connection()
{
    QNetworkReply *reply;
    QNetworkAccessManager dl_manager;

    bool _error=false;
    QString _check_url = "https://www.wikimedia.org";
    QEventLoop loop;
    QObject::connect(&dl_manager,&QNetworkAccessManager::finished,&loop,&QEventLoop::quit);
    reply = dl_manager.get(QNetworkRequest(_check_url));
    loop.exec();

    if (!reply->bytesAvailable())
    {
        _error=true;
    }
    else
    {
        _error=false;
    }

    reply->close();
    loop.exit();

    if(_error==true)
    {
        return false;
    }

    return true;
}
