#include "PgConstraintContainer.h"
#include "Pgsql_Col.h"
#include <algorithm>
#include <iterator>

std::string PgConstraintContainer::getLoadQuery() const
{
	std::string q =  R"__(
SELECT oid, conname, connamespace, contype, condeferrable,
	condeferred, convalidated, conrelid, contypid, conindid,
	confrelid, confupdtype, confdeltype, confmatchtype,
	conislocal, coninhcount, connoinherit, conkey, confkey,
	conpfeqop, conppeqop, conffeqop, conexclop, conbin,
	pg_get_constraintdef(oid)
FROM pg_constraint)__";

//	auto cat = m_catalog.lock();
//	if (cat && cat->serverVersion() >= 90400)
//		q += ", indisreplident ";
//	q += "\nFROM pg_index";
	return q;
}



PgConstraint PgConstraintContainer::loadElem(const Pgsql::Row &row)
{
	using namespace Pgsql;
	Col col(row);
	Oid oid = col.nextValue();
	QString name = col.nextValue();
	Oid ns_oid = col.nextValue();
	PgConstraint v(m_catalog, oid, name, ns_oid);
	col >> v.type >> v.deferrable
		>> v.deferred >> v.validated >> v.relid >> v.typid >> v.indid
		>> v.frelid >> v.fupdtype >> v.fdeltype >> v.fmatchtype
		>> v.islocal >> v.inhcount >> v.noinherit
		>> v.key >> v.fkey >> v.pfeqop >> v.ppeqop >> v.ffeqop >> v.exclop
		>> v.bin >> v.definition;
	return v;
}

std::vector<PgConstraint> PgConstraintContainer::getFKeyForTableColumn(Oid relid, int16_t attnum) const
{
	//const PgConstraint *result = nullptr;
	std::vector<PgConstraint> result;
	// WHat do we want to find here? On ly single column constraints or all contstraints.
	auto res = std::copy_if(m_container.begin(), m_container.end(), std::back_inserter(result),
		[relid, attnum] (const auto &c) {
			// the find on v.key may not look super efficient but remember it in general only has one or two elements.
			return c.type == ConstraintType::ForeignKey && relid == c.relid &&
					(std::find(c.key.begin(), c.key.end(), attnum) != c.key.end());
		});
	return result;
}

std::vector<PgConstraint> PgConstraintContainer::getConstraintsForRelation(Oid relid) const
{
	std::vector<PgConstraint> result;
	std::copy_if(m_container.begin(), m_container.end(), std::back_inserter(result),
				 [relid] (auto && item) { return item.relid == relid; });
	return result;
}

std::optional<PgConstraint> PgConstraintContainer::getPrimaryForRelation(Oid relid) const
{
	std::optional<PgConstraint> result;
	for (const auto &e : m_container) {
		if (e.relid == relid && e.type == ConstraintType::PrimaryKey) {
			result = e;
			break;
		}
	}
	return result;
}

std::vector<PgConstraint> PgConstraintContainer::getReferencedForRelation(Oid relid) const
{
	std::vector<PgConstraint> result;
    std::copy_if(m_container.begin(), m_container.end(), std::back_inserter(result),
				 [relid] (auto && item) { return item.frelid == relid; });
    return result;
}

std::vector<PgConstraint> PgConstraintContainer::getSupportedByIndex(Oid indexrelid) const
{
    std::vector<PgConstraint> result;
    std::copy_if(m_container.begin(), m_container.end(), std::back_inserter(result),
                 [indexrelid] (auto && item) { return item.indid == indexrelid; });
    return result;
}
