/**
 * Copyright (c) 2014-2026 Governikus GmbH & Co. KG, Germany
 */

#pragma once

#include "CVCertificateBody.h"

#include <QByteArrayList>
#include <QDateTime>
#include <QDebug>
#include <QList>
#include <QSharedPointer>


class test_StatePreVerification;


namespace governikus
{

/*!
 * According to
 *    - TR-03110-3, chapter C.1 and
 *    - TR-03110-3, chapter D.2 and
 *
 * CVCertificate ::= APPLICATION [0x21] IMPLICIT SEQUENCE {
 *      body CVCertificateBody,
 *      signature SIGNATURE
 * }
 *
 * SIGNATURE ::= APPLICATION [0x37] IMPLICIT OCTET STRING
 *
 */


struct SIGNATURE
	: public ASN1_OCTET_STRING
{
	// we use inheritance, because the structure ValidityDate is already a typedef of ASN1_OCTET_STRING
	// and we cannot have two template specializations for the same type.
};


using CVCertificate = struct cvcertificate_st
{
	friend class ::test_StatePreVerification;

	CVCertificateBody* mBody;
	SIGNATURE* mSignature;

	static QList<QSharedPointer<const cvcertificate_st>> fromRaw(const QByteArrayList& pByteList);
	static QSharedPointer<const cvcertificate_st> fromRaw(const QByteArray& pBytes);
	[[nodiscard]] QByteArray encode() const;

	[[nodiscard]] const CVCertificateBody& getBody() const;
	[[nodiscard]] QByteArray getRawBody() const;
	[[nodiscard]] QByteArray getSignature() const;
	[[nodiscard]] QByteArray getRawSignature() const;

	[[nodiscard]] bool isValidOn(const QDateTime& pValidationDate) const;
	[[nodiscard]] bool isIssuedBy(const cvcertificate_st& pIssuer) const;

	bool operator==(const cvcertificate_st& pOther) const;
	bool operator!=(const cvcertificate_st& pOther) const;
};


inline auto qHash(const CVCertificate& pCvc, size_t pSeed)
{
	return qHash(pCvc.getRawBody() + pCvc.getRawSignature(), pSeed);
}


DECLARE_ASN1_FUNCTIONS(CVCertificate)
DECLARE_ASN1_OBJECT(CVCertificate)


} // namespace governikus


inline auto qHash(const QSharedPointer<const governikus::CVCertificate>& pCvc, size_t pSeed)
{
	return qHash(*pCvc, pSeed);
}


inline bool operator==(const QSharedPointer<const governikus::CVCertificate>& pLeft, const QSharedPointer<const governikus::CVCertificate>& pRight)
{
	return *pLeft == *pRight;
}


QDebug operator<<(QDebug pDbg, const governikus::CVCertificate& pCvc);
QDebug operator<<(QDebug pDbg, const QSharedPointer<const governikus::CVCertificate>& pCvc);
QDebug operator<<(QDebug pDbg, const QList<QSharedPointer<const governikus::CVCertificate>>& pCvcs);
