#ifndef PGPROC_H
#define PGPROC_H

#include "PgNamespaceObject.h"
#include <QString>
#include <libpq-fe.h>
#include "Pgsql_Value.h"
#include <vector>

class Arg {
public:
	enum Mode {
		In, Out, InOut, Variadic, Table
	};

	Oid type;
	Mode mode;
	QString name;
	QString def;

	Arg(Oid t, Mode m, QString n, QString d)
		: type(t), mode(m), name(n), def(d)
	{}
};


enum class ProcKind {
	Function,  // f Normal function
	Procedure, // p stored procedure, new in 11 can use transactions executed with CALL
	Aggregate, // a
	Window     // w
};

void operator<<(ProcKind &s, const Pgsql::Value &v);

enum class ParallelMode {
	Unsafe, // u, default
	Restricted, // r,
	Safe // s
};

void operator<<(ParallelMode &s, const Pgsql::Value &v);

/**
 * @brief parallelModeToSql
 * @param pm The parallel mode
 * @param explicit_unsafe When false an empty string is return for unsage when true
 *    a "PARALLEL UNSAFE" is returned.
 * @return
 */
QString parallelModeToSql(ParallelMode pm, bool explicit_unsafe = false);


class PgProc: public PgNamespaceObject {
public:
	using PgNamespaceObject::PgNamespaceObject;

	Oid lang = InvalidOid; // oid
	float cost = 0.f; // float4
	float rows = 0.f; // float4
	Oid variadic = InvalidOid; // oid
	ProcKind kind = ProcKind::Function; // >= 11
	bool secdef = false; // bool
	bool leakproof = false; // bool
	bool isstrict = false; // bool
	bool retset = false; // bool
	char provolatile = '\0'; // char
	ParallelMode parallel = ParallelMode::Unsafe; // char, version >= 9.6
	int16_t nargs = 0; // int2
	int16_t nargdefaults; // = 0; // int2
	Oid rettype = InvalidOid; // oid
	std::vector<Oid> trftypes; // oid[], version >= 9.5
	QString src; // text
	QString bin; // text
	std::vector<QString> config; // text[]

	/// Converts the collection of arrays about the arguments to a single list of arguments
	/// making it much easier to work with them correctly
	void setArgs(
		std::vector<Oid> argtypes,
		std::vector<Oid> allargtypes,
		std::vector<char> argmodes,
		std::vector<QString> argnames,
		std::optional<QString> argdefaults
		);
	const std::vector<Arg>& args() const;

	QString createSql() const override;
	QString argListWithNames(bool multiline = false) const;
	QString argSigList(const bool forScript = false) const;
	QString volatility() const;

	bool isFunction()  const { return kind == ProcKind::Function; }
	bool isProcedure() const { return kind == ProcKind::Procedure; }
	bool isAggregate() const { return kind == ProcKind::Aggregate; }
	bool isWindow()    const { return kind == ProcKind::Window; }

	QString typeName() const override;
	QString aclAllPattern() const override;
//	bool isTrigger() const
//	{
//		return typname == wxT("\"trigger\"") || typname == wxT("trigger") || typname == wxT("event_trigger") || typname == wxT("\"event_trigger\""))
//	}
private:
	mutable QString createSqlCache;

	std::vector<Arg> m_args;
};

#endif // PGPROC_H
