package in.gov.digilocker.uidai.services.client;

import java.security.KeyStore;
import java.util.Base64;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import in.gov.digilocker.uidai.logs.fpmodal.BiomatricData;
import in.gov.digilocker.uidai.logs.modal.EKYC;
import in.gov.digilocker.uidai.services.docsigner.DocSigner;
import in.gov.digilocker.uidai.services.properties.EKYCProperties;
import in.gov.digilocker.uidai.services.properties.OTPAuthProperties;
import in.gov.digilocker.uidai.services.properties.UIDAIProps;
import in.gov.digilocker.uidai.services.resources.PostData;
import in.gov.digilocker.uidai.services.resources.RDEncrypter;
import in.gov.digilocker.uidai.services.resources.Utilities;
import in.gov.digilocker.uidai.web.properties.DigilockerProperties;

@Service
public class EKYCClient {		
	
	private static final Logger logger = LoggerFactory.getLogger(EKYCClient.class);	
	public JSONObject verifyEkycAadhaarUsingOtp(EKYCClient ekycClient, UIDAIProps uidaiProps, DigilockerProperties digilockerProps, EKYCProperties ekycProps, AuthClient authClient, OTPAuthProperties authProps,  EKYC ekyc, String reqTimeStamp) throws RuntimeException, Exception {
		JSONObject jObject= new JSONObject();
		logger.info("EKYC Using OTP and AUTH 2.5 process called.");				
		try {			
			if("Y".equals(ekyc.getPdf().toUpperCase())) {
				logger.info("uidai process called with PDF Data.");
				ekycProps.setPfrVal("Y");
			} else {
				ekycProps.setPfrVal("N");
			}
			
			String contentType = "application/xml";		
			
			RDEncrypter enc = new RDEncrypter(uidaiProps.getUidaiCertPath());	
			
			KeyStore.PrivateKeyEntry keyEntry = enc.getKeyFromKeyStore(digilockerProps.getDigilockerCertPath(), digilockerProps.getDigilockerCertPassword(), digilockerProps.getDigilockerCertAlias());
			if (keyEntry == null) {
				throw new RuntimeException("ERR-107, KeyFinder.getKeyFromKeyStore has returned null value.");
			}
			
			String wadhVal = Utilities.sha256String((ekycProps.getEkycVer() + ekycProps.getRaVal() + ekyc.getConsent() + ekycProps.getLrVal() + ekycProps.getDeVal() + ekycProps.getPfrVal()).trim());
			
			String pidxml=	authClient.generatePIDBlock(ekyc.getOtp(), reqTimeStamp, uidaiProps.getUidaiPIDVer(), wadhVal);			
			
			byte[] sessionKey = enc.generateSessionKey();
			byte[] encryptedSessionKey = enc.encryptUsingPublicKey(sessionKey);
			byte[] pidXmlBytes = pidxml.getBytes(uidaiProps.getEncodingType());
			byte[] encXMLPIDData = enc.encrypt(pidXmlBytes, sessionKey, reqTimeStamp);
			
			byte[] iv = enc.generateIv(reqTimeStamp);
			byte[] aad = enc.generateAad(reqTimeStamp);
			byte[] hmac = enc.generateHash(pidXmlBytes);
			byte[] encryptedHmacBytes = enc.encryptDecryptUsingSessionKey(true, sessionKey, iv, aad, hmac);
			
			String certificate_expiry = enc.getCertificateIdentifier();
			
			String authXML = authClient.createOTPAuthRequest(uidaiProps, authProps, ekyc.getAadhaarNumber(), ekyc.getUniqueReqId(), ekyc.getConsent(), certificate_expiry, encryptedSessionKey, encryptedHmacBytes, encXMLPIDData);
			
			String reqKycXML = new EKYCClient().generateEkycXML(uidaiProps, ekycProps, reqTimeStamp, ekyc.getConsent(), authXML);			
			
			jObject.put("request_data", reqKycXML);
			
			String signedKycXML = DocSigner.signXML(reqKycXML, true, keyEntry);
			
			if (digilockerProps.isExceptionEnabled()) {
				logger.info("EKYC Request XML is:- " + reqKycXML);
			}		      
			Utilities.checkProxy(digilockerProps.isProxy(), digilockerProps.getProxyHost(), digilockerProps.getProxyPort());			
			
			String uidaiResponse= new PostData().excutePostXml(uidaiProps.getUidaiServiceUrl(), signedKycXML, contentType);			
			
			if (digilockerProps.isExceptionEnabled()) {
				logger.info("EKYC Response XML is:- " + uidaiResponse);
			}
			
			jObject.put("response_data", uidaiResponse );
			
			return  jObject;
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
	}
	
	public JSONObject verifyEkycAadhaarUsingFingerPrint(EKYCClient ekycClient, UIDAIProps uidaiProps, DigilockerProperties digilockerProps, EKYCProperties ekycProps, AuthClient
			authClient, OTPAuthProperties authProps, EKYC ekyc, BiomatricData biomatricResponse,  String reqTimeStamp) throws RuntimeException, Exception {
		logger.info("EKYC Using Finger Print and AUTH 2.5 process called.");
				
		try {
			
			if("Y".equals(ekyc.getPdf().toUpperCase())) {
				ekycProps.setPfrVal("Y");
			} else {
				ekycProps.setPfrVal("N");
			}
			
			ekycProps.setRaVal("F");			
			authProps.setBioUses("y");
			authProps.setOtpUses("n");
			authProps.setBtUses("FMR");
			authProps.setTid("registered");
			
			String contentType = "application/xml";			
			
			RDEncrypter enc = new RDEncrypter(uidaiProps.getUidaiCertPath());	
			
			KeyStore.PrivateKeyEntry keyEntry = enc.getKeyFromKeyStore(digilockerProps.getDigilockerCertPath(), digilockerProps.getDigilockerCertPassword(), digilockerProps.getDigilockerCertAlias());
			if (keyEntry == null) {
				throw new RuntimeException("ERR-107, KeyFinder.getKeyFromKeyStore has returned null value.");
			}
			
			String authXML = authClient.createFPAuthRequest(digilockerProps, uidaiProps, authProps, ekyc.getAadhaarNumber(), ekyc.getUniqueReqId(), ekyc.getConsent(), biomatricResponse);
			
			String reqKycXML = new EKYCClient().generateEkycXML(uidaiProps, ekycProps, reqTimeStamp, ekyc.getConsent(), authXML);			
			
			String signedKycXML = DocSigner.signXML(reqKycXML, true, keyEntry);
			
			if (digilockerProps.isExceptionEnabled()) {
				logger.info("EKYC Request XML is:- " + reqKycXML);
			}
			
			
			
			Utilities.checkProxy(digilockerProps.isProxy(), digilockerProps.getProxyHost(), digilockerProps.getProxyPort());			
			
			String uidaiResponse= new PostData().excutePostXml(uidaiProps.getUidaiServiceUrl(), signedKycXML, contentType);			
			
			if (digilockerProps.isExceptionEnabled()) {
				logger.info("EKYC Response XML is:- " + uidaiResponse);
			}
			
			JSONObject jObject= new JSONObject();
			jObject.put("request_data", reqKycXML);
			jObject.put("response_data", uidaiResponse );
			
			return  jObject;
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
	}
	
	
	private String generateEkycXML(UIDAIProps uidaiProps1, EKYCProperties ekycProperties1, String ts, String rc, String authXML) throws Exception {
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		Document document = docBuilder.newDocument();
		document.setXmlVersion("1.0");
		document.setXmlStandalone(true);
		Element rootElement = document.createElement("Kyc");
		rootElement.setAttribute("xmlns", ekycProperties1.getEkycXmlns());
		rootElement.setAttribute("ver", ekycProperties1.getEkycVer());
		rootElement.setAttribute("rc", rc);
		rootElement.setAttribute("ra", ekycProperties1.getRaVal());
		rootElement.setAttribute("lr", ekycProperties1.getLrVal());
		rootElement.setAttribute("de", ekycProperties1.getDeVal());
		rootElement.setAttribute("pfr", ekycProperties1.getPfrVal());
		Element radElement = document.createElement("Rad");
		radElement.setTextContent(Base64.getEncoder().encodeToString(authXML.getBytes(uidaiProps1.getEncodingType())));
		rootElement.appendChild(radElement);
		document.appendChild(rootElement);
		String ekycXML = Utilities.convertDocumentToString(document);
		return ekycXML;
	}
}
