#include <cstddef>               // for NULL
#include <qabstractitemview.h>    // for QAbstractItemView, QAbstractItemVie...
#include <qevent.h>               // for QMouseEvent
#include <qglobal.h>              // for foreach
#include <qheaderview.h>          // for QHeaderView, QHeaderView::ResizeToC...
#include <qitemselectionmodel.h>  // for QItemSelection
#include <qnamespace.h>           // for NoModifier, AscendingOrder
#include <qvariant.h>             // for QVariant, QVariant::String

#include "packagelistitem.h"      // for PackageListItem
#include "packagelistmodel.h"     // for PackageListModel
#include "portagelistview.h"

class QWidget;

PortageListView::PortageListView(QWidget *parent)
 : QTreeView(parent)
{
	setRootIsDecorated(false);
	setUniformRowHeights(true);
	setAllColumnsShowFocus(true);
	setSelectionMode(QAbstractItemView::ExtendedSelection);
	setSelectionBehavior(QAbstractItemView::SelectRows);
	setAlternatingRowColors(true);

	auto *m = new PackageListModel(this);
	QHeaderView *hh = header();
	hh->setSectionResizeMode(QHeaderView::ResizeToContents);
	hh->setStretchLastSection(true);
	setModel(m);
}

PortageListView::~PortageListView()
= default;

void PortageListView::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
{
	// declaring a local const container prevents detaching and the attendant clazy warning
	// In C++20 the range for can do this in the loop declaration https://www.kdab.com/blog-qasconst-and-stdas_const/
	const QModelIndexList deselectedindexes = deselected.indexes();
	for(const QModelIndex index : deselectedindexes)
	{
		if (index.column() == 0 && index.data().canConvert<QString>())
		{
			for(int j = 0; j < m_selectedPackages.count(); j++)
				if (m_selectedPackages[j]->name() == index.data().toString())
					m_selectedPackages.removeAt(j);
		}
	}
	// declaring a local const container prevents detaching and the attendant clazy warning
	// In C++20 the range for can do this in the loop declaration https://www.kdab.com/blog-qasconst-and-stdas_const/
	const QModelIndexList selectedindexes = selected.indexes();
	for(const QModelIndex index : selectedindexes )
	{
		if (index.column() == 0 && index.data().canConvert<QString>())
		{
			auto *item = static_cast<PackageListItem*>(index.internalPointer());
			if (item)
				m_selectedPackages << item;
		}
	}

	Q_EMIT selectionChangedSignal();
}

auto PortageListView::selectedPackages() const -> QList<PackageListItem*>
{
	return m_selectedPackages;
}

auto PortageListView::currentPackage() -> PackageListItem*
{
	if (m_selectedPackages.count() != 1)
		return nullptr;
	return m_selectedPackages.at(0);
}

auto PortageListView::packageItemById(const QString& id) -> PackageListItem*
{
	//QMap will insert a default-constructed value if it doesn't already exist
	if (m_packageIndex.contains(id)) {
		return m_packageIndex[id];
	}
	return nullptr;
}

auto PortageListView::selectedPackagesByIds() -> QStringList
{
	QStringList ret;
	for(const PackageListItem *item : std::as_const(m_selectedPackages))
		ret << item->id();

	return ret;
}

void PortageListView::setPackages(const QStringList& packages)
{
	QList<PackageListItem*> items;
	QListIterator<QString> it(packages);
	while( it.hasNext() ) {
		QString id = it.next();
		QString name = it.next();
		QString category = it.next();
		QString description = it.next();
		QString status = it.next();
		QString update = it.next();

		items << new PackageListItem(name, id, category, description, status.toInt(), update, this);
		m_packageIndex.insert(id, items.last());
		m_packageIndex[id]->setPackageIndex(m_packageIndex.count());
	}

	dynamic_cast<PackageListModel*>(model())->setPackages(items);

	//QHeaderView *hh = header();
	//hh->setStretchLastSection(true);
	//hh->resizeSections(QHeaderView::ResizeToContents);

	sortByColumn(0, Qt::AscendingOrder);
}

void PortageListView::mouseDoubleClickEvent(QMouseEvent *event)
{
	QModelIndex index = indexAt(event->pos());
	if (!index.isValid())
		return;

	auto *item = static_cast<PackageListItem*>(index.internalPointer());
	if (!item)
		return;

	Q_EMIT doubleClickedSignal(item);
}

/**
 * Move to next package in listview.
 * @param isPrevious true is previous, false is next
 */
void PortageListView::nextPackage( const bool isPrevious )
{
	if ( isVisible() ) {
		QModelIndex item;
		if ( isPrevious )
			item = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier);
		else
			item = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);

		if (item.isValid()) {
			//qDebug() << static_cast<PackageListItem*>(item.internalPointer())->index();
			scrollTo(item);
			setCurrentIndex(item);
		}
	}
}

