/*
    SPDX-FileCopyrightText: 2007 Glenn Ergeerts <glenn.ergeerts@telenet.be>
    SPDX-FileCopyrightText: 2012 Marco Gulino <marco.gulino@xpeppers.com>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include "faviconfromblob.h"

#include "bookmarks_debug.h"
#include "bookmarksrunner_defs.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QPainter>
#include <QPixmap>
#include <QStandardPaths>

#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <qloggingcategory.h>

std::unique_ptr<Favicon> FaviconFromBlob::chrome(const QString &profileDirectory)
{
    QString profileName = QFileInfo(profileDirectory).fileName();
    QString faviconCache = QStringLiteral("%1/bookmarksrunner/KRunner-Chrome-Favicons-%2.sqlite")
                               .arg(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation), profileName);
    auto fetchSqlite = std::make_unique<FetchSqlite>(faviconCache);

    QString faviconQuery;
    if (fetchSqlite->tables().contains(QLatin1String("favicon_bitmaps"))) {
        faviconQuery = QLatin1String(
            "SELECT * FROM favicons "
            "inner join icon_mapping on icon_mapping.icon_id = favicons.id "
            "inner join favicon_bitmaps on icon_mapping.icon_id = favicon_bitmaps.icon_id "
            "WHERE page_url = :url ORDER BY height desc LIMIT 1;");
    } else {
        faviconQuery = QLatin1String(
            "SELECT * FROM favicons "
            "inner join icon_mapping on icon_mapping.icon_id = favicons.id "
            "WHERE page_url = :url LIMIT 1;");
    }

    return std::make_unique<FaviconFromBlob>(profileName, faviconQuery, QStringLiteral("image_data"), std::move(fetchSqlite));
}

std::unique_ptr<Favicon> FaviconFromBlob::firefox(std::unique_ptr<FetchSqlite> &&fetchSqlite)
{
    QString faviconQuery = QStringLiteral(
        "SELECT moz_icons.data FROM moz_icons"
        " INNER JOIN moz_icons_to_pages ON moz_icons.id = moz_icons_to_pages.icon_id"
        " INNER JOIN moz_pages_w_icons ON moz_icons_to_pages.page_id = moz_pages_w_icons.id"
        " WHERE moz_pages_w_icons.page_url = :url LIMIT 1;");
    return std::make_unique<FaviconFromBlob>(QStringLiteral("firefox-default"), faviconQuery, QStringLiteral("data"), std::move(fetchSqlite));
}

std::unique_ptr<Favicon> FaviconFromBlob::falkon(const QString &profileDirectory)
{
    const QString dbPath = profileDirectory + QStringLiteral("/browsedata.db");
    auto fetchSqlite = std::make_unique<FetchSqlite>(dbPath);
    const QString faviconQuery = QStringLiteral("SELECT icon FROM icons WHERE url = :url LIMIT 1;");
    return std::make_unique<FaviconFromBlob>(QStringLiteral("falkon-default"), faviconQuery, QStringLiteral("icon"), std::move(fetchSqlite));
}

FaviconFromBlob::FaviconFromBlob(const QString &profileName, const QString &query, const QString &blobColumn, std::unique_ptr<FetchSqlite> &&fetchSqlite)
    : Favicon()
    , m_query(query)
    , m_blobcolumn(blobColumn)
    , m_fetchsqlite(std::move(fetchSqlite))
{
    m_profileCacheDirectory =
        QStringLiteral("%1/bookmarksrunner/KRunner-Favicons-%2").arg(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation), profileName);
    // qDebug() << "got cache directory: " << m_profileCacheDirectory;
    cleanCacheDirectory();
    ensureCacheDirectory();
}

FaviconFromBlob::~FaviconFromBlob()
{
    cleanCacheDirectory();
}

void FaviconFromBlob::prepare()
{
    m_fetchsqlite->prepare();
}

void FaviconFromBlob::teardown()
{
    m_fetchsqlite->teardown();
}

void FaviconFromBlob::ensureCacheDirectory()
{
    QDir().mkpath(m_profileCacheDirectory);
}

void FaviconFromBlob::cleanCacheDirectory()
{
    QDir(m_profileCacheDirectory).removeRecursively();
}

QIcon FaviconFromBlob::iconFor(const QString &url)
{
    // qDebug() << "got url: " << url;
    QString fileChecksum = QString::number(qChecksum(url.toLatin1()));
    QFile iconFile(m_profileCacheDirectory + QDir::separator() + fileChecksum + QStringLiteral("_favicon"));
    if (iconFile.size() == 0)
        iconFile.remove();
    if (!iconFile.exists()) {
        ensureCacheDirectory();

        QMap<QString, QVariant> bindVariables;
        bindVariables.insert(QStringLiteral(":url"), url);
        QList<QVariantMap> faviconFound = m_fetchsqlite->query(m_query, bindVariables);
        if (faviconFound.isEmpty())
            return defaultIcon();

        QByteArray iconData = faviconFound.constFirst().value(m_blobcolumn).toByteArray();
        // qDebug() << "Favicon found: " << iconData.size() << " bytes";
        if (iconData.size() <= 0)
            return defaultIcon();

        if (!iconFile.open(QFile::WriteOnly)) {
            qCWarning(RUNNER_BOOKMARKS) << "Chrome runner: could not open iconFile " << iconFile.fileName() << " for writing.";
            return defaultIcon();
        }
        iconFile.write(iconData);
        iconFile.close();
    }
    return QIcon(iconFile.fileName());
}

#include "moc_faviconfromblob.cpp"
