/*
 * Copyright (C) 2014-2024 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 <QDialog>
#include <QItemSelection>
#include <QList>
#include <QSet>
#include <QString>

#include "src/datovka_shared/identifiers/account_id.h"
#include "src/datovka_shared/settings/records_management.h"
#include "src/identifiers/message_id.h"
#include "src/models/backup_selection_model.h"
#include "src/models/message_found_model.h"
#include "src/models/sort_filter_proxy_model.h"
#include "src/records_management/content/automatic_upload_target.h"

namespace Ui {
	class DlgRecordsManagementCheckMsgs;
}

class MainWindow; /* Forward declaration. */
class MessageDbSet; /* Forward declaration. */
class MsgId; /* Forward declaration. */
class QAction; /* Forward declaration. */

/*!
 * @brief Encapsulated records management service check and upload dialogue.
 */
class DlgRecordsManagementCheckMsgs : public QDialog {
	Q_OBJECT

public:
	/*!
	 * @brief Describes local account information.
	 */
	class LocAcntData {
	public:
		LocAcntData(const QString &aName, const AcntId &aId,
		    MessageDbSet *dSet)
		    : accountName(aName), acntId(aId), dbSet(dSet)
		{
		}

		QString accountName; /*!< Account name. */
		AcntId acntId; /*!< Account identifier. */
		MessageDbSet *dbSet; /*!< Database set related to account. */
	};

private:
	/*!
	 * @brief Constructor.
	 *
	 * @param[in] recMgmtSettings Records management settings.
	 * @param[in] accounts Accounts data list.
	 * @param[in] mw Pointer to main window.
	 * @param[in] parent Parent widget.
	 */
	explicit DlgRecordsManagementCheckMsgs(
	    const RecordsManagementSettings &recMgmtSettings,
	    const QList<LocAcntData> &accounts, MainWindow *mw,
	    QWidget *parent = Q_NULLPTR);

public:
	/*!
	 * @brief Destructor.
	 */
	virtual
	~DlgRecordsManagementCheckMsgs(void);

	/*!
	 * @brief Open dialogue.
	 *
	 * @param[in] recMgmtSettings Records management settings.
	 * @param[in] accounts Accounts data list.
	 * @param[in] mw Pointer to main window.
	 * @param[in] parent Parent widget.
	 */
	static
	void openDlg(const RecordsManagementSettings &recMgmtSettings,
	    const QList<LocAcntData> &accounts, MainWindow *mw,
	    QWidget *parent = Q_NULLPTR);

protected:
	/*!
	 * @brief Check window geometry and set table columns width.
	 *
	 * @param[in] event Widget show event.
	 */
	virtual
	void showEvent(QShowEvent *event) Q_DECL_OVERRIDE;

private slots:
	/*!
	 * @brief Change selection according to all checkbox state.
	 */
	void applyAllSelection(int state);

	/*!
	 * @brief Filter account list.
	 *
	 * @param[in] text Sought text.
	 */
	void filterAccount(const QString &text);

	/*!
	 * @brief Filter message list.
	 *
	 * @param[in] text Sought text.
	 */
	void filterMessage(const QString &text);

	/*!
	 * @brief Update dialogue when account selection changes.
	 */
	void modifiedAccountSelection(void);

	/*!
	 * @brief Update calendar limits.
	 */
	void reflectCalendarChange(void);

	/*!
	 * @brief Enable/disable calendar according to checkbox state.
	 *
	 * @param[in] state Check box state.
	 */
	void enableCanlendars(int state);

	/*!
	 * @brief Update dialogue when download state changes.
	 */
	void modifiedMessageDownloadStatus(void);

	/*!
	 * @brief Update dialogue when number of (unfiltered) listed messages changes.
	 */
	void messageListLengthChanged(void);

/* Window state change. */
	/*!
	 * @brief Updates message selection.
	 *
	 * @param[in] selected Newly selected indexes.
	 * @param[in] deselect Deselected indexes.
	 */
	void updateMessageSelection(const QItemSelection &selected,
	    const QItemSelection &deselected = QItemSelection());

/* Mouse on view clicks. */
	/*!
	 * @brief Emit ID of message entry.
	 *
	 * @param[in] index Model index.
	 */
	void messageItemDoubleClicked(const QModelIndex &index);

	/*!
	 * @brief Generates a context menu depending on the item and selection
	 *     it was invoked on.
	 *
	 * @param[in] point Invocation position.
	 */
	void viewMessageListContextMenu(const QPoint &point);

/* Handle database signals. */
	/*!
	 * @brief Update window data when complete message has been written
	 *     to database.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgId Message identifier.
	 * @param[in] direction Sent or received messages
	 *                      (enum MessageDirection).
	 */
	void watchMessageInserted(const AcntId &acntId, const MsgId &msgId,
	    int direction);

	/*!
	 * @brief Update window data when message deleted.
	 *
	 * @param[in] acntId Account identifier.
	 * @param[in] msgId Message identifier.
	 */
	void watchMessageDataDeleted(const AcntId &acntId, const MsgId &msgId);

	/*!
	 * @brief Update model data when  entry has been changed.
	 *
	 * @param[in] dmId Message identifier.
	 * @param[in] locations List of locations.
	 */
	void watchRmMsgEntryUpdated(qint64 dmId, const QStringList &locations);

/* Message menu. */
	/*!
	 * @brief Downloads attachments of selected messages.
	 */
	void downloadSelectedMessageAttachments(void);

	/*!
	 * @brief Send message to records management.
	 */
	void viewSendSelectedMessageToRecordsManagementDlg(void);

/* Button actions. */
	/*!
	 * @brief Search for messages not in records management.
	 */
	void checkUploadedMsgs(void);

	/*!
	 * @brief Automatic upload to records management.
	 */
	void uploadMsgsToRm(void);

	/*!
	 * @brief Export missing records management messages.
	 */
	void exportMsgs(void);

/* Close dialogue. */
	/*!
	 * @brief Abort upload loop.
	 */
	void abortUpload(void);

signals:
	/*!
	 * @brief Signals that a message was selected should be focused
	 *     elsewhere.
	 *
	 * @param[in] username Username identifying an account.
	 * @param[in] testing True if this is an testing account.
	 * @param[in] dmId Message identifier.
	 * @param[in] year Message delivery year.
	 * @param[in] msgType Message type.
	 */
	void focusSelectedMsg(AcntId acntId, qint64 dmId, QString year,
	    int msgType);

private:
	/*!
	 * @brief Set up menu actions.
	 */
	void setupActions(void);

	/*!
	 * @brief Connect database container signals to appropriate slots.
	 */
	void databaseConnectActions(void);

	/*!
	 * @brief Update list of uploaded message from records management.
	 *
	 * @param[in] selectedAccounts List of selected accounts.
	 */
	void updateUploadedMsgRmList(const QList<LocAcntData> &selectedAccounts);

	/*!
	 * @brief Get upload hierarchy of records management.
	 *
	 * @return Records management upload targets hierarchy.
	 */
	const RecMgmt::AutomaticUploadTarget getRmHierarchy(void);

	/*!
	 * @brief Prepare list of messages to be uploaded into records management.
	 *
	 * @param[in] selectedAccounts List of selected accounts.
	 * @param[in] rmUploadedMsgs List of messages from records management database.
	 * @param[in] from From delivery date.
	 * @param[in] to To delivery date.
	 */
	void fillMsgRmUploadList(const QList<LocAcntData> &selectedAccounts,
	    const QSet<qint64> &rmUploadedMsgs, const QDate &from,
	    const QDate &to);

	/*!
	 * @brief Enable actions according to status.
	 */
	void updateActionActivation(void);

	Ui::DlgRecordsManagementCheckMsgs *m_ui; /*!< UI generated from UI file. */

	QAction *m_actionDownloadMessage; /*!< Download message. */
	QAction *m_actionSendToRecordsManagement; /*!< Send to records management. */

	MainWindow *m_mw;  /*!< Pointer to main window. */

	const RecordsManagementSettings m_recMgmtSettings;/*!< Records management settings. */
	const QList<LocAcntData> &m_accounts; /*!< Accounts data list. */
	RecMgmt::AutomaticUploadTarget m_recMgmtTargets; /*!< Automatic records management upload targets. */

	QList<int> m_msgModelRowSelection; /*!< Holds the message selection. */

	SortFilterProxyModel m_accountListProxyModel; /*!<
	                                               * Used for account
	                                               * sorting and filtering.
	                                               */
	QString m_dfltAccountFilerLineStyleSheet; /*!< Used to remember default line edit style. */
	BackupSelectionModel m_accountSelectionModel; /*!< Choose account data to scan. */

	SortFilterProxyModel m_messageListProxyModel; /*!<
	                                               * Used for message
	                                               * sorting and filtering.
	                                               */
	QString m_dfltMessageFilerLineStyleSheet; /*!< Used to remember default line edit style. */
	MsgFoundModel m_foundTableModel; /*!< Model of found message table. */
	int m_uploadInfoCol; /*!< Upload status column index. */

	volatile bool m_abortUpload; /*!< Signals whether to abort the upload loop. */
};
