#ifndef FZ_SERIALIZATION_TYPES_SECURABLE_SOCKET_CERT_INFO_HPP
#define FZ_SERIALIZATION_TYPES_SECURABLE_SOCKET_CERT_INFO_HPP

#include "../../securable_socket.hpp"
#include "../helpers.hpp"
#include "optional.hpp"
#include "acme.hpp"
#include "variant.hpp"

namespace fz {

template <typename Archive>
void serialize(Archive &ar, securable_socket::user_provided_cert_info &ci)
{
	using namespace serialization;

	ar(
		value_info(nvp(ci.key_path,
					   "keyfile"),
					   "Path to the private key in PEM format."),

		value_info(nvp(ci.certs_path,
					   "certsfile"),
					   "Path to the certificates file in PEM format."),

		value_info(optional_nvp(ci.password,
								"password"),
								"Password to decrypt private key. *DO NOT USE FOR NEWLY CREATED CERTIFICATES* *ONLY USE WHEN IMPORTING OLD SERVER CONFIG*")

	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::uploaded_cert_info &ci)
{
	using namespace serialization;

	ar(
		value_info(nvp(ci.key_path,
					   "keyfile"),
					   "Path to the private key in PEM format."),

		value_info(nvp(ci.certs_path,
					   "certsfile"),
					   "Path to the certificates file in PEM format."),

		value_info(optional_nvp(ci.password,
								"password"),
								"Password to decrypt private key. *DO NOT USE FOR NEWLY CREATED CERTIFICATES* *ONLY USE WHEN IMPORTING OLD SERVER CONFIG*")

	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::autogenerated_cert_info &ci)
{
	using namespace serialization;

	ar(
		value_info(nvp(ci.fingerprint,
					   "fingerprint"),
					   "Fingerprint of the autogenerated and selfsigned certificate.")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::acme_cert_info &ci)
{
	using namespace serialization;

	ar(
		value_info(nvp(ci.account_id,
					   "account_id"),
					   "Kid of the ACME account associated with the certificate"),
		value_info(nvp(ci.hostnames,
					   "", "host"),
					   "Hosts the certificate is valid for."),
		value_info(optional_nvp(ci.autorenew,
								"autorenew"),
								"Whether to automatically attempt the renewal of the certificate.")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::exported_cert_info &ci)
{
	using namespace serialization;

	ar(
		value_info(nvp(ci.original,
					   "original"),
					   "The original certificate being exported"),
		value_info(nvp(ci.key,
					   "key"),
					   "The certs private key. If empty, it is assumed that they key is embedded in the certs."),
		value_info(nvp(ci.certs,
					   "certs"),
					   "The certs chain. If key is empty, it is assumed that certs also contains the key itself.")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::autogenerated_cert_info::extra &e)
{
	using namespace serialization;

	ar(
		nvp(e.distinguished_name, "distinguished_name"),
		nvp(e.hostnames, "hostnames"),
		nvp(e.activation_time, "activation_time"),
		nvp(e.expiration_time, "expiration_time")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::user_provided_cert_info::extra &e)
{
	using namespace serialization;

	ar(
		nvp(e.fingerprint, "fingerprint"),
		nvp(e.distinguished_name, "distinguished_name"),
		nvp(e.hostnames, "hostnames"),
		nvp(e.activation_time, "activation_time"),
		nvp(e.expiration_time, "expiration_time")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::uploaded_cert_info::extra &e)
{
	using namespace serialization;

	ar(
		nvp(e.fingerprint, "fingerprint"),
		nvp(e.distinguished_name, "distinguished_name"),
		nvp(e.hostnames, "hostnames"),
		nvp(e.activation_time, "activation_time"),
		nvp(e.expiration_time, "expiration_time")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::acme_cert_info::extra &e)
{
	using namespace serialization;

	ar(
		nvp(e.fingerprint, "fingerprint"),
		nvp(e.distinguished_name, "distinguished_name"),
		nvp(e.account, "account"),
		nvp(e.activation_time, "activation_time"),
		nvp(e.expiration_time, "expiration_time")
	);
}

}

FZ_SERIALIZATION_NAME_OF_TYPE_ALL(fz::tls_param::blob_type, "blob")
FZ_SERIALIZATION_NAME_OF_TYPE_ALL(fz::tls_param::filepath_type, "filepath")
FZ_SERIALIZATION_NAME_OF_TYPE_ALL(fz::tls_param::pkcs11url_type, "pkcs11url")

namespace fz::serialization {

template <typename Archive>
std::enable_if_t<!trait::is_textual_v<Archive>>
serialize(Archive &ar, tls_param::blob_type &v)
{
	ar(nvp(v.value, ""));
}

template <typename Archive>
std::enable_if_t<trait::is_textual_v<Archive>>
load(Archive &ar, tls_param::blob_type &v)
{
	bool base64{};

	ar.attribute(base64, "base64")(
		nvp(v.value, "")
	);

	if (ar && base64) {
		v.value = base64_decode_s(v.value);
	}
}

template <typename Archive>
std::enable_if_t<trait::is_textual_v<Archive>>
save(Archive &ar, const tls_param::blob_type &v)
{
	bool base64 = !is_pem(v.value);

	if (ar.attribute(base64, "base64")) {
		const std::string &value = base64
			? base64_encode(v.value, base64_type::standard, false)
			: v.value;

		ar(value_info(nvp(value, ""), "The data of a key or certificates chain in PEM or DER format"));
	}
}

template <typename Archive>
void serialize(Archive &ar, tls_param::filepath_type &v)
{
	ar(value_info(nvp(v.value, ""), "The path to a key or a certificates chain on the file system"));
}

template <typename Archive>
void serialize(Archive &ar, tls_param::pkcs11url_type &v)
{
	ar(value_info(nvp(v.value, ""), "A PKCS#11 URL referencing a key or a certificates chain"));
}

template <typename Archive>
void serialize(Archive &ar, fz::tls_param &v)
{
	ar(nvp(with_type_as_index(v.value), ""));
}

template <typename Archive>
void serialize(Archive &, securable_socket::omni_cert_info::sources::provided &)
{
}

template <typename Archive>
void serialize(Archive &, securable_socket::omni_cert_info::sources::autogenerated &)
{
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::omni_cert_info::sources::acme &s)
{
	ar(
		value_info(nvp(s.account_id,
					   "account_id"),
					   "Kid of the ACME account associated with the certificate"),

		value_info(optional_nvp(s.autorenew,
								"autorenew"),
								"Whether to automatically attempt the renewal of the certificate.")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::omni_cert_info &ci)
{
	ar(
		value_info(nvp(ci.key,
					   "key"),
					   "The private key"),

		value_info(nvp(ci.certs,
					   "certs"),
					   "The certificates chain"),

		value_info(optional_nvp(ci.key_password,
								"key_password"),
								"Password to decrypt/access the private key"),

		value_info(optional_nvp(ci.source,
								"source"),
								"The source of this key/certs pair")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::omni_cert_info::extra &e)
{
	ar(
		nvp(e.fingerprint, "fingerprint"),
		nvp(e.distinguished_name, "distinguished_name"),
		nvp(e.hostnames, "hostnames"),
		nvp(e.activation_time, "activation_time"),
		nvp(e.expiration_time, "expiration_time")
	);
}

template <typename Archive>
void serialize(Archive &ar, securable_socket::info &i)
{
	ar.optional_attribute(i.min_tls_ver, "min_protocol_version")(
		nvp(i.cert, "")
	);

	if constexpr (trait::is_input_v<Archive>) {
		if (i.min_tls_ver < tls_ver::v1_2)
			i.min_tls_ver = tls_ver::v1_2;
	}
}

}

#endif // FZ_SERIALIZATION_TYPES_SECURABLE_SOCKET_CERT_INFO_HPP
