#include "ConstraintModel.h"
#include "ScopeGuard.h"
#include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgConstraintContainer.h"
#include "Pgsql_oids.h"

ConstraintModel::ConstraintModel(QObject *parent)
	: BaseTableModel(parent)
{
}

void ConstraintModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const std::optional<PgClass> &table)
{
	if (cat != m_catalog) {
	   m_catalog = cat;
	   refreshConnection = connect(m_catalog.get(), &PgDatabaseCatalog::refreshed, this, &ConstraintModel::refresh);
	}
	m_table = table;
	refresh();
}

void ConstraintModel::refresh()
{
	beginResetModel();
	SCOPE_EXIT { endResetModel(); };

	if (m_table) {
		m_constraints = m_catalog->constraints()->getConstraintsForRelation(m_table->oid());
		std::sort(m_constraints.begin(), m_constraints.end(),
				  [] (auto &l, auto &r) {
						return l.type < r.type ||
							(l.type == r.type && l.objectName() < r.objectName());
			});
	}
	else
		m_constraints.clear();
}

QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	QVariant v;
	if (orientation == Qt::Horizontal) {
		if (role == Qt::DisplayRole) {
			QString c;
			switch (section) {
			case TypeCol:
				c = tr("Type");
				break;
			case NameCol:
				c = tr("Name");
				break;
			case NsCol:
				c = tr("Schema");
				break;
			case SupportingIndexCol:
				c = tr("Supporting index");
				break;
            case InheritedCol:
                c = tr("Inherited");
                break;
//			case DefinitionCol:
//				c = tr("Definition");
//				break;
			}
			v = c;
		}
	}
	return v;
}

int ConstraintModel::rowCount(const QModelIndex &) const
{
    return static_cast<int>(m_constraints.size());
}

int ConstraintModel::columnCount(const QModelIndex &) const
{
	return colCount;
}

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

//	// FIXME: Implement me!
//	return v;
//}

Oid ConstraintModel::getType(int col) const
{
    Oid oid;
    switch (col) {
    case InheritedCol:
        oid = Pgsql::bool_oid;
        break;
    default:
        oid = Pgsql::varchar_oid;
    }
    return oid;
}

QString IconForConstraintType(ConstraintType ct)
{
	QString s = ":/icons/constraints/";
	switch (ct) {
	case ConstraintType::Check:
		s += "check.png";
		break;
	case ConstraintType::ForeignKey:
		s += "foreignkey.png";
		break;
	case ConstraintType::PrimaryKey:
		s += "primarykey.png";
		break;
	case ConstraintType::Unique:
		s += "unique.png";
		break;
	case ConstraintType::ConstraintTrigger:
		s = "CT";
		break;
	case ConstraintType::ExclusionConstraint:
		s = "XC";
		break;
	default:
		s = "?";
		break;
	}
	return s;
}

QVariant ConstraintModel::getData(const QModelIndex &index) const
{
	QVariant v;
	const int row = index.row();
	const auto &t = m_constraints[row];

	const int col = index.column();

    switch (col) {
	case TypeCol:
        v = IconForConstraintType(t.type);
		break;
	case NameCol:
        v = t.objectName();
		break;
	case NsCol:
        v = t.nsName();
		break;
	case SupportingIndexCol:
        v = getIndexDisplayString(*m_catalog, t.indid);
		break;
    case InheritedCol:
        v = t.isInherited();
        break;
//	case DefinitionCol:
//		s = t.definition;
//		break;
	}

	return v;
}

const PgConstraint& ConstraintModel::constraint(int row)
{
	return m_constraints[row];
}
