// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "externalllmloader_p.h"

#include <QDirIterator>
#include <QSettings>
#include <QStandardPaths>

#include <QDebug>

using namespace uos_ai;

ExternalLLMLoaderPrivate::ExternalLLMLoaderPrivate(ExternalLLMLoader *parent) : q(parent)
{

}


ExternalLLMLoader::ExternalLLMLoader(QObject *parent)
    : QObject(parent)
    , d(new ExternalLLMLoaderPrivate(this))
{
    QStringList paths{EXTERNAL_LLM_DIR};
    d->loadPaths = paths;
}

ExternalLLMLoader::~ExternalLLMLoader()
{
    delete d;
    d = nullptr;
}

void ExternalLLMLoader::setPaths(const QStringList &paths)
{
    d->loadPaths = paths;
}

void ExternalLLMLoader::readPlugins()
{
    d->llmPlugins.clear();
    d->loaders.clear();

    for (const QString &path : d->loadPaths) {
        QDirIterator dirItera(path, { "*.so" },
                              QDir::Filter::Files,
                              QDirIterator::IteratorFlag::NoIteratorFlags);
        while (dirItera.hasNext()) {
            dirItera.next();
             const QString &fileName { dirItera.path() + "/" + dirItera.fileName() };
            QSharedPointer<QPluginLoader> loader(new QPluginLoader);
            loader->setFileName(fileName);

            QJsonObject &&metaJson = loader->metaData();
            QString &&iid = metaJson.value("IID").toString();

            if (iid == LLMPlugin_Meta_IID) {
                if (!loader->load()) {
                    qWarning() << loader->errorString();
                    continue;
                }

                LLMPlugin *llm = dynamic_cast<LLMPlugin *>(loader->instance());
                if (!llm) {
                    qCritical() << loader->fileName() << "has no LLMPlugin.";
                    loader->unload();
                    continue;
                }

                d->llmPlugins.append(QSharedPointer<LLMPlugin>(llm));
                d->loaders.append(loader);
            }
        }
    }
}

QList<QSharedPointer<LLMPlugin> > ExternalLLMLoader::plugins() const
{
    return d->llmPlugins;
}
