/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.commons.domain.model.platform;

import java.security.cert.X509Certificate;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.certificates.configuration.X509CertificateValidationResult;
import com.scytl.cryptolib.certificates.cryptoapi.CryptoAPIX509Certificate;
import com.scytl.cryptolib.certificates.factory.CryptoX509Certificate;
import com.scytl.cryptolib.primitives.primes.utils.PemUtils;
import com.scytl.products.ov.commons.beans.domain.model.platform.PlatformInstallationData;
import com.scytl.products.ov.commons.beans.exceptions.DuplicateEntryException;
import com.scytl.products.ov.commons.beans.validation.CertificateValidationService;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.domain.model.BaseRepository;

public class PlatformInstallationDataHandler {

	private PlatformInstallationDataHandler() {
		super();
	}

	public static <T extends PlatformCAEntity> String savePlatformCertificateChain(final PlatformInstallationData data,
			final BaseRepository<T, Long> repository,
			CertificateValidationService certificateValidationService, final T platformRoot,
			final T issuerCert) {
		try {

			String issuerCertificateData = data.getPlatformRootIssuerCaPEM();
			CryptoAPIX509Certificate issuerCryptoAPIX509Certificate;

			String platformCertificateData = data.getPlatformRootCaPEM();
			X509Certificate platformCertificate = (X509Certificate) PemUtils
					.certificateFromPem(platformCertificateData);

			CryptoAPIX509Certificate cryptoAPIX509Certificate = new CryptoX509Certificate(platformCertificate);
			if (issuerCertificateData != null && !issuerCertificateData.isEmpty()) {
				X509Certificate issuerCertificate = (X509Certificate) PemUtils
						.certificateFromPem(issuerCertificateData);
				issuerCryptoAPIX509Certificate = new CryptoX509Certificate(issuerCertificate);

				X509CertificateValidationResult validateCertificateChain = 
						validateCertificateChain(issuerCryptoAPIX509Certificate, cryptoAPIX509Certificate,
						certificateValidationService);
				if (!validateCertificateChain.isValidated()) {
					throw new IllegalStateException("Certificate validation failed for the following validation types: "
							+ validateCertificateChain.getFailedValidationTypes().toString());
				}
				saveToRepository(repository, issuerCertificateData, issuerCryptoAPIX509Certificate, issuerCert);
			} else {
				X509CertificateValidationResult validationResult = validateSingleCertificate(cryptoAPIX509Certificate,
						certificateValidationService);
				if (!validationResult.isValidated()) {
					throw new IllegalStateException("Certificate validation failed for the following validation types: "
							+ validationResult.getFailedValidationTypes().toString());
				}
			}

			saveToRepository(repository, platformCertificateData, cryptoAPIX509Certificate, platformRoot);
			return cryptoAPIX509Certificate.getSubjectDn().getOrganization();
		} catch (IllegalArgumentException | SecurityException | DuplicateEntryException | GeneralCryptoLibException
				| CryptographicOperationException e) {
			throw new IllegalStateException("Error while trying to initialize platformroot", e);
		}
	}

	private static <T extends PlatformCAEntity> void saveToRepository(final BaseRepository<T, Long> repository,
			String platformCertificateData, CryptoAPIX509Certificate cryptoAPIX509Certificate,
			T platformCaEntity) throws DuplicateEntryException {

		String platformName = cryptoAPIX509Certificate.getSubjectDn().getOrganization();
		String certificateName = cryptoAPIX509Certificate.getSubjectDn().getCommonName();

		platformCaEntity.setCertificateName(certificateName);
		platformCaEntity.setCertificateContent(platformCertificateData);
		platformCaEntity.setPlatformName(platformName);
		repository.save(platformCaEntity);
	}

	public static X509CertificateValidationResult validateSingleCertificate(
			CryptoAPIX509Certificate cryptoAPIX509Certificate,
			CertificateValidationService certificateValidationService) throws CryptographicOperationException {
		return certificateValidationService.validateRootCertificate(cryptoAPIX509Certificate.getCertificate());
	}

	public static X509CertificateValidationResult validateCertificateChain(CryptoAPIX509Certificate issuerCryptoAPIX509Certificate,
			CryptoAPIX509Certificate cryptoAPIX509Certificate,
			CertificateValidationService certificateValidationService)
			throws GeneralCryptoLibException, CryptographicOperationException {
		return certificateValidationService.validateIntermediateCACertificate(
				cryptoAPIX509Certificate.getCertificate(), issuerCryptoAPIX509Certificate.getCertificate());

	}
}
