/*
 * Copyright (C) 2014-2020 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.
 */

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>

#include "src/datovka_shared/json/helper.h"
#include "src/datovka_shared/records_management/json/upload_account_status.h"

static
const QString keyBoxId("box_id");
static
const QString keyUserId("user_id");
static
const QString keyTime("time");
static
const QString keyDmCntRcvdNotAccepted("dm_cnt_rcvd_not_accepted");
static
const QString keyDmCntSntNotAccepted("dm_cnt_snt_not_accepted");
static
const QString keyDmCntRcvdNotInRm("dm_cnt_rcvd_not_in_rm");
static
const QString keyDmCntSntNotInRm("dm_cnt_snt_not_in_rm");
static
const QString keyUserAccountName("user_account_name");

static
const QString keyError("error");

RecMgmt::UploadAccountStatusReq::UploadAccountStatusReq(void)
    : m_boxId(),
    m_userId(),
    m_time(),
    m_rcvdNotAccepted(-1),
    m_sntNotAccepted(-1),
    m_rcvdNotInRegMgmt(-1),
    m_sntNotInRegMgmt(-1),
    m_userAccountName()
{
}

RecMgmt::UploadAccountStatusReq::UploadAccountStatusReq(const QString &boxId,
    const QString &userId, const QDateTime &time, int rcvdNotAccepted,
    int sntNotAccepted, int rcvdNotInRegMgmt, int sntNotInRegMgmt,
    const QString &userAccountName)
    : m_boxId(boxId),
    m_userId(userId),
    m_time(time),
    m_rcvdNotAccepted(rcvdNotAccepted),
    m_sntNotAccepted(sntNotAccepted),
    m_rcvdNotInRegMgmt(rcvdNotInRegMgmt),
    m_sntNotInRegMgmt(sntNotInRegMgmt),
    m_userAccountName(userAccountName)
{
}

RecMgmt::UploadAccountStatusReq::UploadAccountStatusReq(
    const UploadAccountStatusReq &other)
    : m_boxId(other.m_boxId),
    m_userId(other.m_userId),
    m_time(other.m_time),
    m_rcvdNotAccepted(other.m_rcvdNotAccepted),
    m_sntNotAccepted(other.m_sntNotAccepted),
    m_rcvdNotInRegMgmt(other.m_rcvdNotInRegMgmt),
    m_sntNotInRegMgmt(other.m_sntNotInRegMgmt),
    m_userAccountName(other.m_userAccountName)
{
}

const QString &RecMgmt::UploadAccountStatusReq::boxId(void) const
{
	return m_boxId;
}

const QString &RecMgmt::UploadAccountStatusReq::userId(void) const
{
	return m_userId;
}

const QDateTime &RecMgmt::UploadAccountStatusReq::time(void) const
{
	return m_time;
}

int RecMgmt::UploadAccountStatusReq::rcvdNotAccepted(void) const
{
	return m_rcvdNotAccepted;
}

int RecMgmt::UploadAccountStatusReq::sntNotAccepted(void) const
{
	return m_sntNotAccepted;
}

int RecMgmt::UploadAccountStatusReq::rcvdNotInRegMgmt(void) const
{
	return m_rcvdNotInRegMgmt;
}

int RecMgmt::UploadAccountStatusReq::sntNotInRegMgmt(void) const
{
	return m_sntNotInRegMgmt;
}

const QString &RecMgmt::UploadAccountStatusReq::userAccountName(void) const
{
	return m_userAccountName;
}

bool RecMgmt::UploadAccountStatusReq::isValid(void) const
{
	return (!m_boxId.isEmpty()) && (!m_userId.isEmpty()) &&
	    m_time.isValid() && (m_rcvdNotAccepted >= 0) &&
	    (m_sntNotAccepted >= 0) && (m_rcvdNotInRegMgmt >= 0) &&
	    (m_sntNotInRegMgmt >= 0);
	/* User account name may be null. */
}

RecMgmt::UploadAccountStatusReq RecMgmt::UploadAccountStatusReq::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (!Json::Helper::readRootObject(json, jsonObj)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	UploadAccountStatusReq uasr;

	if (!Json::Helper::readString(jsonObj, keyBoxId, uasr.m_boxId,
	        Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readString(jsonObj, keyUserId, uasr.m_userId,
	        Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readQDateTimeString(jsonObj, keyTime, uasr.m_time,
	        Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readInt(jsonObj, keyDmCntRcvdNotAccepted,
	        uasr.m_rcvdNotAccepted, Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readInt(jsonObj, keyDmCntSntNotAccepted,
	        uasr.m_sntNotAccepted, Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readInt(jsonObj, keyDmCntRcvdNotInRm,
	        uasr.m_rcvdNotInRegMgmt, Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readInt(jsonObj, keyDmCntSntNotInRm,
	        uasr.m_sntNotInRegMgmt, Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (!Json::Helper::readString(jsonObj, keyUserAccountName,
	        uasr.m_userAccountName, Json::Helper::ACCEPT_NULL)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusReq();
	}

	if (ok != Q_NULLPTR) {
		*ok = true;
	}
	return uasr;
}

QByteArray RecMgmt::UploadAccountStatusReq::toJson(void) const
{
	QJsonObject jsonObj;
	jsonObj.insert(keyBoxId, !m_boxId.isNull() ? m_boxId : QJsonValue());
	jsonObj.insert(keyUserId, !m_userId.isNull() ? m_userId : QJsonValue());
	/*
	 * Intentionally using UTC because Qt gets a bit schizophrenic when
	 * generating ISO 8601 formatted time strings:
	 * https://stackoverflow.com/q/21976264
	 *
	 * m_time.toOffsetFromUtc(m_time.offsetFromUtc()).toString(Qt::ISODate)
	 */
	jsonObj.insert(keyTime,
	    m_time.isValid() ? m_time.toUTC().toString(Qt::ISODate) : QJsonValue());
	jsonObj.insert(keyDmCntRcvdNotAccepted,
	    (m_rcvdNotAccepted >= 0) ? m_rcvdNotAccepted : QJsonValue());
	jsonObj.insert(keyDmCntSntNotAccepted,
	    (m_sntNotAccepted >= 0) ? m_sntNotAccepted : QJsonValue());
	jsonObj.insert(keyDmCntRcvdNotInRm,
	    (m_rcvdNotInRegMgmt >= 0) ? m_rcvdNotInRegMgmt : QJsonValue());
	jsonObj.insert(keyDmCntSntNotInRm,
	    (m_sntNotInRegMgmt >= 0) ? m_sntNotInRegMgmt : QJsonValue());
	jsonObj.insert(keyUserAccountName,
	    !m_userAccountName.isNull() ? m_userAccountName : QJsonValue());

	return QJsonDocument(jsonObj).toJson(QJsonDocument::Indented);
}

RecMgmt::UploadAccountStatusResp::UploadAccountStatusResp(void)
    : m_error()
{
}

RecMgmt::UploadAccountStatusResp::UploadAccountStatusResp(const ErrorEntry &error)
    : m_error(error)
{
}

RecMgmt::UploadAccountStatusResp::UploadAccountStatusResp(
    const UploadAccountStatusResp &other)
    : m_error(other.m_error)
{
}

const RecMgmt::ErrorEntry &RecMgmt::UploadAccountStatusResp::error(void) const
{
	return m_error;
}

bool RecMgmt::UploadAccountStatusResp::isValid(void) const
{
	return true; /* Any value is valid. */
}

RecMgmt::UploadAccountStatusResp RecMgmt::UploadAccountStatusResp::fromJson(
    const QByteArray &json, bool *ok)
{
	QJsonObject jsonObj;
	if (!Json::Helper::readRootObject(json, jsonObj)) {
		if (ok != Q_NULLPTR) {
			*ok = false;
		}
		return UploadAccountStatusResp();
	}

	UploadAccountStatusResp uasr;

	{
		QJsonValue jsonVal;
		if (!Json::Helper::readValue(jsonObj, keyError, jsonVal)) {
			if (ok != Q_NULLPTR) {
				*ok = false;
			}
			return UploadAccountStatusResp();
		}
		if (!uasr.m_error.fromJsonVal(&jsonVal)) {
			if (ok != Q_NULLPTR) {
				*ok = false;
			}
			return UploadAccountStatusResp();
		}
	}

	if (ok != Q_NULLPTR) {
		*ok = true;
	}
	return uasr;
}

QByteArray RecMgmt::UploadAccountStatusResp::toJson(void) const
{
	QJsonObject jsonObj;
	QJsonValue jsonVal;
	m_error.toJsonVal(&jsonVal);
	jsonObj.insert(keyError, jsonVal);

	return QJsonDocument(jsonObj).toJson(QJsonDocument::Indented);
}
