/*
 * 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.
 */

#include <QJsonObject>
#include <QJsonValue>

#include "src/datovka_shared/compat/compiler.h" /* macroStdMove */
#include "src/datovka_shared/isds/json_conversion.h"
#include "src/datovka_shared/isds/type_conversion.h"
#include "src/datovka_shared/json/helper.h"

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

	return personName2FromJsonVal(jsonObj, ok);
}

static const QString keyPnGivenNames("pnGivenNames");
static const QString keyPnLastName("pnLastName");

Isds::PersonName2 Isds::Json::personName2FromJsonVal(const QJsonValue &jsonVal,
    bool *ok)
{
	PersonName2 pn2;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();

		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyPnGivenNames,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			pn2.setGivenNames(valStr);
		}
		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyPnLastName,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			pn2.setLastName(valStr);
		}
	}

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

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return PersonName2();
}

bool Isds::Json::toJsonVal(const PersonName2 &n, QJsonValue &jsonVal)
{
	QJsonObject jsonObj;

	jsonObj.insert(keyPnGivenNames, (!n.givenNames().isEmpty()) ? n.givenNames() : QJsonValue());
	jsonObj.insert(keyPnLastName, (!n.lastName().isEmpty()) ? n.lastName() : QJsonValue());

	jsonVal = jsonObj;
	return true;
}

QByteArray Isds::Json::toJsonData(const PersonName2 &n, bool indent)
{
	QJsonValue jsonVal;
	if (toJsonVal(n, jsonVal)) {
		return ::Json::Helper::toJsonData(jsonVal, indent);
	} else {
		return QByteArray();
	}
}

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

	return dmMessageAuthorFromJsonVal(jsonObj, ok);
}

static const QString keyUserType("userType");
static const QString keyPersonName("personName");
static const QString keyBiDate("biDate");
static const QString keyBiCity("biCity");
static const QString keyBiCounty("biCounty");
static const QString keyAdCode("adCode");
static const QString keyFullAddress("fullAddress");
static const QString keyRobIdent("robIdent");

Isds::DmMessageAuthor Isds::Json::dmMessageAuthorFromJsonVal(
    const QJsonValue &jsonVal, bool *ok)
{
	DmMessageAuthor dma;

	if (Q_UNLIKELY(!jsonVal.isObject())) {
		goto fail;
	}

	{
		const QJsonObject jsonObj = jsonVal.toObject();

		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyUserType,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setUserType(str2SenderType(valStr));
		}
		{
			QJsonValue jsonVal;
			if (::Json::Helper::readValue(jsonObj, keyPersonName,
			        jsonVal, ::Json::Helper::ACCEPT_NULL)) {
				bool iOk = false;
				dma.setPersonName(personName2FromJsonVal(jsonVal, &iOk));
				if (Q_UNLIKELY(!iOk)) {
					goto fail;
				}
			} else {
				goto fail;
			}
		}
		{
			QDate valDate;
			if (::Json::Helper::readQDateString(jsonObj, keyBiDate,
			        valDate, ::Json::Helper::ACCEPT_NULL)) {
				dma.setBiDate(macroStdMove(valDate));
			} else {
				goto fail;
			}
		}
		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyBiCity,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setBiCity(macroStdMove(valStr));
		}
		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyBiCounty,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setBiCounty(macroStdMove(valStr));
		}
		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyAdCode,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setAdCode(macroStdMove(valStr));
		}
		{
			QString valStr;
			if (Q_UNLIKELY(!::Json::Helper::readString(jsonObj, keyFullAddress,
			        valStr, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setFullAddress(macroStdMove(valStr));
		}
		{
			enum Type::NilBool valNilBool = Type::BOOL_NULL;
			if (Q_UNLIKELY(!::Json::Helper::readNilBool(jsonObj,
			        keyRobIdent, valNilBool, ::Json::Helper::ACCEPT_NULL))) {
				goto fail;
			}
			dma.setRobIdent(valNilBool);
		}
	}

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

fail:
	if (ok != Q_NULLPTR) {
		*ok = false;
	}
	return DmMessageAuthor();
}

bool Isds::Json::toJsonVal(const DmMessageAuthor &auth, QJsonValue &jsonVal)
{
	QJsonObject jsonObj;

	{
		const QString &typeStr = senderType2Str(auth.userType());
		jsonObj.insert(keyUserType, (!typeStr.isEmpty()) ? typeStr : QJsonValue());
	}
	{
		QJsonValue jsonVal;
		if (Q_UNLIKELY(!toJsonVal(auth.personName(), jsonVal))) {
			goto fail;
		}
		jsonObj.insert(keyPersonName, jsonVal);
	}
	jsonObj.insert(keyBiDate,
	    auth.biDate().isValid() ? auth.biDate().toString(Qt::ISODate) : QJsonValue());
	jsonObj.insert(keyBiCity, (!auth.biCity().isEmpty()) ? auth.biCity() : QJsonValue());
	jsonObj.insert(keyBiCounty, (!auth.biCounty().isEmpty()) ? auth.biCounty() : QJsonValue());
	jsonObj.insert(keyAdCode, (!auth.adCode().isEmpty()) ? auth.adCode() : QJsonValue());
	jsonObj.insert(keyFullAddress, (!auth.fullAddress().isEmpty()) ? auth.fullAddress() : QJsonValue());
	jsonObj.insert(keyRobIdent, (auth.robIdent() != Isds::Type::BOOL_NULL) ?
	    QJsonValue(auth.robIdent() == Isds::Type::BOOL_TRUE) : QJsonValue());

	jsonVal = jsonObj;
	return true;

fail:
	jsonVal = QJsonObject();
	return false;
}

QByteArray Isds::Json::toJsonData(const DmMessageAuthor &auth, bool indent)
{
	QJsonValue jsonVal;
	if (toJsonVal(auth, jsonVal)) {
		return ::Json::Helper::toJsonData(jsonVal, indent);
	} else {
		return QByteArray();
	}
}
