#include "FolderListModel.h"
#include <QDebug>

// --- FolderTreeItem ---

FolderTreeItem::FolderTreeItem(Type type, QVariant data, FolderTreeItem *parent)
    : m_type(type), m_data(std::move(data)), m_parentItem(parent)
{
}

FolderTreeItem::~FolderTreeItem()
{
    qDeleteAll(m_childItems);
}

void FolderTreeItem::appendChild(FolderTreeItem *child)
{
    m_childItems.append(child);
}

void FolderTreeItem::clearChildren()
{
    qDeleteAll(m_childItems);
    m_childItems.clear();
}

FolderTreeItem *FolderTreeItem::child(int row)
{
    if (row < 0 || row >= m_childItems.size())
        return nullptr;
    return m_childItems.at(row);
}

int FolderTreeItem::childCount() const
{
    return m_childItems.size();
}

int FolderTreeItem::row() const
{
    if (m_parentItem)
        return m_parentItem->m_childItems.indexOf(const_cast<FolderTreeItem*>(this));
    return 0;
}

FolderTreeItem *FolderTreeItem::parentItem() const
{
    return m_parentItem;
}

// --- FolderListModel ---

FolderListModel::FolderListModel(AccountService *accountService, QObject *parent)
    : QAbstractItemModel(parent),
      m_accountService(accountService),
      m_rootItem(new FolderTreeItem(FolderTreeItem::AccountNode, QStringLiteral("Root")))
{
    refresh();
    // Connect to account list changes
    if (m_accountService) {
        connect(m_accountService, &AccountService::accountListChanged,
                this, &FolderListModel::onAccountListChanged);
    }
}

FolderListModel::~FolderListModel()
{
    delete m_rootItem;
}

QModelIndex FolderListModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    FolderTreeItem *parentItem;
    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<FolderTreeItem*>(parent.internalPointer());

    FolderTreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    return QModelIndex();
}

QModelIndex FolderListModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    FolderTreeItem *childItem = static_cast<FolderTreeItem*>(index.internalPointer());
    FolderTreeItem *parentItem = childItem->parentItem();

    if (!parentItem || parentItem == m_rootItem)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int FolderListModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;

    FolderTreeItem *parentItem;
    if (!parent.isValid())
        parentItem = m_rootItem;
    else
        parentItem = static_cast<FolderTreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}

int FolderListModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 1;
}

QVariant FolderListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    FolderTreeItem *item = static_cast<FolderTreeItem*>(index.internalPointer());

    if (role == Qt::DisplayRole || role == NameRole) {
        if (item->type() == FolderTreeItem::AccountNode) {
            Account acc = item->data().value<Account>();
            return acc.displayName().isEmpty() ? acc.email() : acc.displayName();
        } else {
            Folder folder = item->data().value<Folder>();
            return folder.name();
        }
    }

    if (role == ItemTypeRole)
        return item->type();

    if (role == AccountIdRole) {
        if (item->type() == FolderTreeItem::AccountNode) {
            Account acc = item->data().value<Account>();
            return acc.id();
        }
    }

    if (role == FolderIdRole) {
        if (item->type() == FolderTreeItem::FolderNode) {
            Folder folder = item->data().value<Folder>();
            return folder.id();
        }
    }

    if (role == UnreadCountRole) {
        if (item->type() == FolderTreeItem::FolderNode) {
            Folder folder = item->data().value<Folder>();
            // TODO: compute unread count
            return 0;
        }
    }

    return QVariant();
}

bool FolderListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    Q_UNUSED(index);
    Q_UNUSED(value);
    Q_UNUSED(role);
    return false;
}

Qt::ItemFlags FolderListModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QHash<int, QByteArray> FolderListModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[Qt::DisplayRole] = "display";
    roles[NameRole] = "name";
    roles[ItemTypeRole] = "itemType";
    roles[AccountIdRole] = "accountId";
    roles[FolderIdRole] = "folderId";
    roles[UnreadCountRole] = "unreadCount";
    return roles;
}

void FolderListModel::refresh()
{
    beginResetModel();
    clearModel();
    setupModelData();
    endResetModel();
}

void FolderListModel::onAccountListChanged()
{
    refresh();
}

void FolderListModel::setupModelData()
{
    if (!m_accountService)
        return;

    QVector<Account> accounts = m_accountService->getAllAccounts();
    for (const Account &acc : accounts) {
        QVariant accData;
        accData.setValue(acc);
        FolderTreeItem *accountItem = new FolderTreeItem(FolderTreeItem::AccountNode, accData, m_rootItem);
        m_rootItem->appendChild(accountItem);

        // Load folders for this account
        QVector<Folder> folders = FolderDao::findByAccountId(acc.id());
        for (const Folder &folder : folders) {
            QVariant folderData;
            folderData.setValue(folder);
            FolderTreeItem *folderItem = new FolderTreeItem(FolderTreeItem::FolderNode, folderData, accountItem);
            accountItem->appendChild(folderItem);
        }
    }
}

void FolderListModel::clearModel()
{
    m_rootItem->clearChildren();
}