#include "emojimodel.h"
#include "emojidata.h"

// https://www.unicode.org/reports/tr51/#def_emoji_presentation_selector
#define VARIATION_SELECTOR_16 0xFE0F
// https://www.unicode.org/reports/tr51/#def_emoji_keycap_sequence
#define KEYCAP_SEQUENCE_SUFFIX 0x20E3

EmojiModel::EmojiModel(QObject *parent) : QAbstractListModel(parent)
{
    auto categories = GeneratedData::emojiCategories();

#if QT_VERSION > QT_VERSION_CHECK(6, 9, 0)
    m_bases = GeneratedData::emojiBasesList();
    m_variants = GeneratedData::emojiVariantsList();
#else
    // Until version 6.9, Qt had a defective unicode segmenter. Removing VS16
    // from the sequence makes it render the emoji correctly
    int keycapCount = 0;
    for (auto &base : GeneratedData::emojiBasesList()) {
        // But for some reason it has issues with the keycap emojis anyway so
        // let's remove them for now
        if (base.endsWith(QChar(KEYCAP_SEQUENCE_SUFFIX))) {
            keycapCount += 1;
            continue;
        }
        m_bases.append(base.remove(QChar(VARIATION_SELECTOR_16)));
    }
    // Move "Flags" back the number of removed keycaps
    categories["Flags"] -= keycapCount;
    auto variants = GeneratedData::emojiVariantsList();
    for (auto it = variants.begin(); it != variants.end(); ++it) {
        QString base(it.key());
        base.remove(QChar(VARIATION_SELECTOR_16));
        for (auto &variant : it.value()) {
            m_variants[base].append(variant.remove(QChar(VARIATION_SELECTOR_16)));
        }
    }
#endif
    for (auto it = categories.begin(); it != categories.end(); ++it) {
        m_categories[it.key()] = QVariant(it.value());
    }
    // TODO: remove once the category list can handle more categories
    // Since the map stores the start index removing an entry "merges" it with
    // the category before it
    m_categories.remove("People & Body");
    Q_EMIT categoriesChanged();
}

QVariant EmojiModel::data(const QModelIndex &index, int role) const
{
    int row = index.row();
    int recentCount = m_recent.count();
    if (!index.isValid() || row >= m_bases.count() + recentCount) {
        return {};
    }

    auto base = row >= recentCount ? m_bases[row - recentCount] : m_recent[row];

    switch (role) {
    case EmojiModel::Roles::Emoji:
        return QVariant(base);
    case EmojiModel::Roles::Variants:
        return QVariant(m_variants.value(base));
    }

    return {};
}

QHash<int, QByteArray> EmojiModel::roleNames() const
{
    QHash<int, QByteArray> roles{
        { EmojiModel::Roles::Emoji, "emoji" },
        { EmojiModel::Roles::Variants, "variants" },
    };
    return roles;
}

int EmojiModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_bases.count() + m_recent.count();
}

// TODO: once recents are managed here and not in QML, use beginMoveRows
// when adding a new one instead of rewriting the list one by one
void EmojiModel::insertRecent(int i, QString emoji)
{
    beginInsertRows(QModelIndex(), i, i);
    m_recent.insert(i, emoji);
    endInsertRows();
    Q_EMIT recentChanged();
}

void EmojiModel::setRecent(int i, QString emoji)
{
    if (i < m_recent.count()) {
        beginRemoveRows(QModelIndex(), i, i);
        m_recent.removeAt(i);
        endRemoveRows();
    }

    insertRecent(i, emoji);
    Q_EMIT recentChanged();
}

QVariantMap EmojiModel::getCategories() const
{
    return m_categories;
}

int EmojiModel::getRecentCount() const
{
    return m_recent.count();
}
