/*
 * Copyright (C) 2024, KylinSoft Co., Ltd.
 *
 * 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/>.
 *
 * Authors: hxf <hewenfei@kylinos.cn>
 *
 */

#include "widget-metadata.h"

#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonValue>
#include <QJsonArray>
#include <QLocale>
#include <QSharedData>

#include <QDebug>

namespace UkuiQuick {

class WidgetMetadataPrivate : public QSharedData
{
public:
    WidgetMetadataPrivate() : m_isValid(false){};
    WidgetMetadataPrivate(const QString &root);
    WidgetMetadataPrivate(const WidgetMetadataPrivate &other)
        : QSharedData(other),
          m_isValid(other.m_isValid),
          m_id(other.m_id),
          m_root(other.m_root),
          m_object(other.m_object)
    {};
    ~WidgetMetadataPrivate() {};

    static QString localeKey(const QString &key);

    bool m_isValid;
    QString m_id;
    QDir m_root;
    QJsonObject m_object;
};

WidgetMetadataPrivate::WidgetMetadataPrivate(const QString& root)
{
    if(root.isEmpty()) {
        return;
    }
    m_root = QDir(root);
    if (!m_root.entryList(QDir::Files).contains("metadata.json")) {
        qWarning() << "loadWidgetPackage: can not find metadata.json, path:" << m_root.path();
        return;
    }

    QFile file(m_root.absoluteFilePath("metadata.json"));
    if (!file.open(QFile::ReadOnly)) {
        return;
    }

    QTextStream iStream(&file);
    iStream.setCodec("UTF-8");

    QJsonParseError parseError {};
    QJsonDocument document = QJsonDocument::fromJson(iStream.readAll().toUtf8(), &parseError);
    file.close();

    if (parseError.error != QJsonParseError::NoError) {
        qWarning() << "metadata.json parse error:" << parseError.errorString();
        return;
    }

    if (!document.isObject()) {
        qWarning() << "metadata.json parse error: Is not object.";
        return;
    }

    QJsonObject object = document.object();
    QJsonValue id = object.value(QLatin1String("Id"));
    if (id.type() == QJsonValue::Undefined) {
        qWarning() << "metadata: Id is undefined.";
        return;
    }

    if ((m_id = id.toString()) != m_root.dirName()) {
        qWarning() << "metadata: dir not equal id.";
        return;
    }

    m_object = object;
    m_isValid = true;
}

QString WidgetMetadataPrivate::localeKey(const QString& key)
{
    return (key + "[" + QLocale::system().name() + "]");
}

WidgetMetadata::WidgetMetadata() : d(new WidgetMetadataPrivate)
{
}

WidgetMetadata::WidgetMetadata(const QString &root) : d(new WidgetMetadataPrivate(root))
{
}

WidgetMetadata::WidgetMetadata(const WidgetMetadata& other): d(other.d)
{
}

const QDir &WidgetMetadata::root() const
{
    return d->m_root;
}

WidgetMetadata& WidgetMetadata::operator=(const WidgetMetadata& other)
{
    d = other.d;
    return *this;
}

bool WidgetMetadata::operator==(const WidgetMetadata& other) const
{
    return d->m_id == other.d->m_id;
}

WidgetMetadata::~WidgetMetadata() = default;

bool WidgetMetadata::isValid() const
{
    return d->m_isValid;
}

QString WidgetMetadata::id() const
{
    return d->m_id;
}

QString WidgetMetadata::icon() const
{
    QJsonValue value = d->m_object.value(QLatin1String("Icon"));
    if (value.type() == QJsonValue::Undefined) {
        return "application-x-desktop";
    }

    return value.toString();
}

QString WidgetMetadata::name() const
{
    QJsonValue value = d->m_object.value(WidgetMetadataPrivate::localeKey("Name"));
    if (value.type() != QJsonValue::Undefined) {
        return value.toString();
    }

    value = d->m_object.value(QLatin1String("Name"));
    if (value.type() == QJsonValue::Undefined) {
        return d->m_id;
    }

    return value.toString();
}

QString WidgetMetadata::tooltip() const
{
    QJsonValue value = d->m_object.value(WidgetMetadataPrivate::localeKey("Tooltip"));
    if (value.type() != QJsonValue::Undefined) {
        return value.toString();
    }

    value = d->m_object.value(QLatin1String("Tooltip"));
    if (value.type() == QJsonValue::Undefined) {
        return d->m_id;
    }

    return value.toString();
}

QString WidgetMetadata::version() const
{
    QJsonValue value = d->m_object.value(QLatin1String("Version"));
    if (value.type() == QJsonValue::Undefined) {
        return "";
    }

    return value.toString();
}

QString WidgetMetadata::website() const
{
    QJsonValue value = d->m_object.value(QLatin1String("Website"));
    if (value.type() == QJsonValue::Undefined) {
        return "";
    }

    return value.toString();
}

QString WidgetMetadata::bugReport() const
{
    QJsonValue value = d->m_object.value(QLatin1String("BugReport"));
    if (value.type() == QJsonValue::Undefined) {
        return "https://gitee.com/openkylin/ukui-panel/issues";
    }

    return value.toString();
}

QString WidgetMetadata::description() const
{
    QJsonValue value = d->m_object.value(WidgetMetadataPrivate::localeKey("Description"));
    if (value.type() != QJsonValue::Undefined) {
        return value.toString();
    }

    value = d->m_object.value(QLatin1String("Description"));
    if (value.type() == QJsonValue::Undefined) {
        return d->m_id;
    }

    return value.toString();
}

QVariantList WidgetMetadata::authors() const
{
    QJsonValue value = d->m_object.value(QLatin1String("Authors"));
    if (value.type() == QJsonValue::Undefined || value.type() != QJsonValue::Array) {
        return {};
    }

    return value.toArray().toVariantList();
}

QVariantMap WidgetMetadata::contents() const
{
    QJsonValue value = d->m_object.value(QLatin1String("Contents"));
    if (value.type() == QJsonValue::Undefined || value.type() != QJsonValue::Object) {
        return {};
    }

    return value.toObject().toVariantMap();
}

WidgetMetadata::Hosts WidgetMetadata::showIn() const
{
    QJsonValue value = d->m_object.value(QLatin1String("ShowIn"));
    if (value.type() == QJsonValue::Undefined || value.type() != QJsonValue::String) {
        return All;
    }
    QStringList hostList = value.toString().split(",");
    if (hostList.isEmpty()) {
        return All;
    }
    Hosts hosts = Undefined;
    for (const QString &host : hostList) {
        if (host == QStringLiteral("Panel")) {
            hosts |= Panel;
        } else if (host == QStringLiteral("SideBar")) {
            hosts |= SideBar;
        } else if (host == QStringLiteral("Desktop")) {
            hosts |= Desktop;
        } else if (host == QStringLiteral("All")) {
            hosts |= All;
        } else if (host == QStringLiteral("TaskManager")) {
            hosts |= TaskManager;
        } else if (host == QStringLiteral("Shortcut")) {
            hosts |= Shortcut;
        } else if (host == QStringLiteral("Wallpaper")) {
            hosts |= Wallpaper;
        } else if (host == QStringLiteral("DesktopView")) {
            hosts |= DesktopView;
        }
    }
    return hosts;
}

Types::WidgetType WidgetMetadata::widgetType() const
{
    QJsonValue value = d->m_object.value(QLatin1String("WidgetType"));
    if (value.toString() == QStringLiteral("Container")) {
        return Types::Container;
    }

    return Types::Widget;
}

QStringList WidgetMetadata::applicationId() const
{
    const QJsonValue value = d->m_object.value(QLatin1String("ApplicationId"));
    if (value.type() == QJsonValue::Undefined || value.type() != QJsonValue::Array) {
        return {};
    }
    QStringList ids;
    for (auto id : value.toArray()) {
        ids.append(id.toString());
    }

    return ids;
}

QString WidgetMetadata::thumbnail() const
{
    const QJsonValue value = d->m_object.value(QLatin1String("Thumbnail"));
    if (value.type() == QJsonValue::Undefined ) {
        return {};
    }
    return value.toString();
}
}
