#pragma once

#include "../common/common.h"
#include "../pki/cert.h"
#include "../pki/certs.h"
#include "../pki/crl.h"
#include "../pki/crls.h"

#include <string.h>

#include "wrapper/store/store_defines.h"
#include "wrapper/store/pkistore.h"

struct ProviderProps
{
	int type;
	Handle<std::string> name;
};

class ContainerName
{
public:
	ContainerName();
	~ContainerName() {};
public:
	Handle<std::string> unique; //CRYPT_UNIQUE
	Handle<std::wstring> container; //PP_CONTAINER
	Handle<std::string> fqcnA; //PP_FQCN
	Handle<std::wstring> fqcnW; //PP_FQCN with mbstowcs
};

class ProviderCryptopro : public Provider
{
public:
	ProviderCryptopro();
	~ProviderCryptopro(){};

public:
	void init();

	Handle<ICertificate> static getCert(Handle<std::string> hash, Handle<std::string> category);
	Handle<ICRL> static getCRL(Handle<std::string> hash, Handle<std::string> category);
	//Handle<Key> static getKey(Handle<Certificate> cert);

	Handle<std::string> addPkiObject(Handle<ICertificate> cert, Handle<std::string> category, Handle<std::string> contName = new std::string(), int provType = 0);
	void deletePkiObject(Handle<ICertificate> cert, Handle<std::string> category);

	Handle<std::string> addPkiObject(Handle<ICRL> crl, Handle<std::string> category);
	void deletePkiObject(Handle<ICRL> crl, Handle<std::string> category);

	static bool hasPrivateKey(Handle<ICertificate> cert);
	static std::string getPrivateKeyName(Handle<ICertificate> cert);

	Handle<ICertificate> getItemCert(Handle<IPkiItem> item);
	Handle<ICRL> getItemCrl(Handle<IPkiItem> item);

	std::vector<int> getSupportedAlgorithms(AlgType algType);
	std::vector<std::string> getSupportedAlgorithmsOids();

	// provider implementation specific methods (moved from Csp class)
	bool isGost2001CSPAvailable();
	bool isGost2012_256CSPAvailable();
	bool isGost2012_512CSPAvailable();

	bool checkCPCSPLicense();
	Handle<std::string> getCPCSPLicense();
	Handle<std::string> getCPCSPVersion();
	Handle<std::string> getCPCSPVersionPKZI();
	Handle<std::string> getCPCSPVersionSKZI();
	Handle<std::string> getCPCSPSecurityLvl();

	std::vector<ProviderProps> enumProviders();
	std::vector<Handle<ContainerName>> enumContainers(int provType, Handle<std::string> provName);
	Handle<ICertificate> getCertificateFromContainer(Handle<std::string> contName, int provType, Handle<std::string> provName);
	Handle<std::string> getContainerNameByCertificate(Handle<ICertificate> cert, Handle<std::string> category);
	void installCertificateFromCloud(
		Handle<Certificate> hcert,
		const std::string& szAuthURL,
		const std::string& szRestURL,
		unsigned certificate_id,
		bool isLM = false
	);
	void installCertificateFromContainer(Handle<std::string> contName, int provType, Handle<std::string> provName);
	void installCertificateToContainer(Handle<ICertificate> cert, Handle<std::string> contName, int provType, Handle<std::string> provName);
	void deleteContainer(Handle<std::string> contName, int provType, Handle<std::string> provName);

	Handle<ICertificateCollection> buildChain(Handle<ICertificate> cert, Handle<ICertificateCollection>* downloadedCerts = NULL);
	bool verifyCertificateChain(Handle<ICertificate> cert, unsigned long* pdwError = NULL);

	bool verifyCRL(Handle<ICRL> crl);

	bool isHaveExportablePrivateKey(Handle<ICertificate> cert);

	Handle<IPKCS12> certToPkcs12(Handle<ICertificate> cert, bool exportPrivateKey, Handle<std::string> pfxPassword, Handle<std::string> keyPassword);
	void importPkcs12(Handle<IPKCS12> p12, Handle<std::string> pfxPassword, Handle<std::string> keyPassword, bool bSilent = false);

	bool static findExistingCertificate(
		OUT PCCERT_CONTEXT& pOutCertContext,
		IN HCERTSTORE hCertStore,
		IN PCCERT_CONTEXT pCertContext,
		IN unsigned long dwFindFlags = 0,
		IN unsigned long dwCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
	);

	bool static findExistingCrl(
		OUT PCCRL_CONTEXT& pOutCrlContext,
		IN HCERTSTORE hCertStore,
		IN PCCRL_CONTEXT pCrlContext,
		IN unsigned long dwFindFlags = 0,
		IN unsigned long dwCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
	);

	LPCWSTR static provTypeToProvNameW(unsigned long dwProvType);
	static Handle<ICertificateCollection> importSST(Handle<std::string> sstFileName);
	static Handle<ICertificateCollection> importSST(BYTE* buffer, unsigned long dwSize);

	static PCCERT_CONTEXT getCertFromStore(Handle<ICertificate> cert);

	bool checkKeyPin(Handle<IPkiItem> itemKey, Handle<std::string> pinToCheck);

private:
	void enumCertificates(HCERTSTORE hCertStore, std::string *category);
	void enumCrls(HCERTSTORE hCertStore, std::string *category);
	Handle<IPkiItem> objectToPKIItem(Handle<ICertificate> cert);
	Handle<IPkiItem> objectToPKIItem(Handle<ICRL> crl);

	int static char2int(char input);
	void static hex2bin(const char* src, char* target);

	bool static cmpCertAndContFP(LPCSTR szContainerName, LPBYTE pbFPCert, unsigned long cbFPCert);

	static bool checkProvIsAvailable(DWORD dwProvType);
	std::vector<std::vector<unsigned char>> enumAlgorithms();
};
