/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#pragma once

#include <QDateTime>
#include <QList>
#include <QObject>

#include "src/datovka_shared/io/sqlite/db_single.h"
#include "src/json/message_id.h"

class AcntId; /* Forward declaration. */
namespace Json {
	class DbInfo; /* Forward declaration. */
	class MsgId2List; /* Forward declaration. */
}

class TstValidity {
public:
	TstValidity(void)
	    : tstTracked(false), tstExpiration()
	{ }

	TstValidity(bool t, const QDateTime &e)
	    : tstTracked(t), tstExpiration(e)
	{ }
#ifdef Q_COMPILER_RVALUE_REFS
	TstValidity(bool t, QDateTime &&e)
	    : tstTracked(t), tstExpiration(::std::move(e))
	{ }
#endif /* Q_COMPILER_RVALUE_REFS */

	bool tstTracked; /* True if identification found. */
	QDateTime tstExpiration; /* Timestamp expiration. */
};

Q_DECLARE_METATYPE(TstValidity)

class TstValidityHash : public QHash<Json::MsgId1, TstValidity> {
public:
	/*
	 * Don't forget to declare types in order to make them work with
	 * the meta-object system.
	 */
	static
	void declareTypes(void);
};

Q_DECLARE_METATYPE(TstValidityHash)

class TstEntry {
public:
	/*
	 * Don't forget to declare types in order to make them work with
	 * the meta-object system.
	 */
	static
	void declareTypes(void);

	TstEntry(void)
	    : msgId(), username(), tstExpiration()
	{ }

	TstEntry(const Json::MsgId2 &m, const QString &u, const QDateTime &e)
	    : msgId(m), username(u), tstExpiration(e)
	{ }
#ifdef Q_COMPILER_RVALUE_REFS
	TstEntry(Json::MsgId2 &&m, QString &&u, QDateTime &&e)
	    : msgId(::std::move(m)), username(::std::move(u)), tstExpiration(::std::move(e))
	{ }
#endif /* Q_COMPILER_RVALUE_REFS */

	Json::MsgId2 msgId;
	QString username;
	QDateTime tstExpiration;
};

Q_DECLARE_METATYPE(TstEntry)
Q_DECLARE_METATYPE(QList<TstEntry>)

/*!
 * @brief Encapsulates timestamp database.
 */
class TimestampDb : public QObject, public SQLiteDbSingle {
	Q_OBJECT

public:
	/* Use parent class constructor. */
	using SQLiteDbSingle::SQLiteDbSingle;

	/*!
	 * @brief Get information about the database.
	 *
	 * @param[out] info Database information.
	 * @return True on success, false on any error.
	 */
	bool getDbInfo(Json::DbInfo &info) const;

	/*!
	 * @brief Update database information.
	 *
	 * @param[in] info Database information.
	 * @return True on success, false on any error.
	 */
	bool updateDbInfo(const Json::DbInfo &info);

	/*!
	 * @brief Insert ZFO identifications
	 *     (i.e. environment, message id and delivery time).
	 *
	 * @note Emits identificationsInserted() when new data inserted.
	 *
	 * @param[in] msgIds Message/delivery info identifiers.
	 * @param[in] acntId Account identifier.
	 * @return True on success, false on any error.
	 */
	bool insertIdentifications(const Json::MsgId2List &msgIds,
	    const AcntId &acntId);

	/*!
	 * @brief Delete ZFO identifications (i.e. environment, message id)
	 *     -- delivery time values are ignored.
	 *
	 * @note Emits identificationsDeleted() when data deleted.
	 *
	 * @param[in] msgIds Message/delivery info identifiers.
	 * @return True on success, false on any error.
	 */
	bool deleteIdentifications(Json::MsgId2List msgIds);

	/*!
	 * @brief Get number of identifications.
	 *
	 * @param[out] cnt Count of identification on the database.
	 * @return True on success, false on any error.
	 */
	bool getIdentificationCnt(qint64 &cnt) const;

	/*!
	 * @brief Get message timestamp expiration time.
	 *
	 * @param[in] msgIds Message identifiers.
	 * @param[out] values Message expiration values.
	 * @return True on success, false on any error.
	 */
	bool getMsgTimestampData(const Json::MsgId1List &msgIds,
	    TstValidityHash &values) const;

	/*!
	 * @brief Update message timestamp expiration time.
	 *
	 * @note Emits msgTimestampDataUpdated().
	 *
	 * @param[in] values Message expiration values.
	 * @return True on success, false on any error.
	 */
	bool updateMsgTimestampData(const TstValidityHash &values);

	/*!
	 * @brief Get nuber of message timestamp entries.
	 *
	 * @param[out] cnt Number of etrnies.
	 * @param[in] expiringFrom List entries with timestamp time >= expiringFrom.
	 *                         Condition is ignored when invalid value is passed.
	 * @param[in] expiringTo List entries with timestamp time < expiringTo.
	 *                       Condition is ignored when invalid value is passed.
	 */
	bool getMsgTimestampCnt(qint64 &cnt,
	    const QDateTime &expiringFrom, const QDateTime &expiringTo) const;

	/*!
	 * @brief Get message timestamp entries suitable for listing.
	 *
	 * @param[out] tstEntries Found entries.
	 * @param[in] expiringFrom List entries with timestamp time >= expiringFrom.
	 *                         Condition is ignored when invalid value is passed.
	 * @param[in] expiringTo List entries with timestamp time < expiringTo.
	 *                       Condition is ignored when invalid value is passed.
	 */
	bool getMsgTimestampListing(QList<TstEntry> &tstEntries,
	    const QDateTime &expiringFrom, const QDateTime &expiringTo) const;

Q_SIGNALS:
	/*!
	 * @brief Emitted when new ZFO identifiers inserted.
	 *
	 * @param[in] msgIds ZFO identifiers.
	 * @param[in] acntId Account identifier.
	 */
	void identificationsInserted(const Json::MsgId2List &msgIds,
	    const AcntId &acntId);

	/*!
	 * @brief Emitted when new ZFO identifiers deleted.
	 *
	 * @param[in] msgIds ZFO identifiers.
	 */
	void identificationsDeleted(const Json::MsgId2List &msgIds);

	/*!
	 * @brief Emitted when message expiration updated.
	 *
	 * @param[in] values Message expiration values.
	 */
	void msgTimestampDataUpdated(const TstValidityHash &values);

protected:
	/*!
	 * @brief Returns list of tables.
	 *
	 * @return List of pointers to tables.
	 */
	virtual
	QList<class SQLiteTbl *> listOfTables(void) const Q_DECL_OVERRIDE;

	/*!
	 * @brief Fixes some database states.
	 *
	 * @brief Adds missing entries or converts database content between
	 *     versions.
	 *
	 * @return True on success.
	 */
	virtual
	bool assureConsistency(void) Q_DECL_OVERRIDE;

	/*!
	 * @brief Enables foreign key support.
	 *
	 * @note Foreign key functionality is not enabled by default at runtime.
	 *     https://sqlite.org/foreignkeys.html
	 *
	 * @return True on success.
	 */
	virtual
	bool enableFunctionality(void) Q_DECL_OVERRIDE;
};
