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

import java.security.KeyStore;
import java.util.Map.Entry;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import in.gov.digilocker.uidai.logs.modal.OTP;
import in.gov.digilocker.uidai.services.docsigner.DocSigner;
import in.gov.digilocker.uidai.services.properties.OTPProperties;
import in.gov.digilocker.uidai.services.properties.UIDAIProps;
import in.gov.digilocker.uidai.services.properties.UidaiErrors;
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.services.xmlresponse.OTPResponse;
import in.gov.digilocker.uidai.web.properties.DigilockerProperties;

@Service
public class OTPClient {
	
	private static final Logger logger= LoggerFactory.getLogger(OTPClient.class);	
	@Autowired UIDAIProps uidaiProps;
	@Autowired DigilockerProperties digilockerProps;
	@Autowired OTPProperties otpProperties;
	@Autowired UidaiErrors uidaiErrors;
	
	public OTPResponse sendOTPRequestToUID(OTP otpModel, String reqTimeStamp) throws RuntimeException, Exception {
		//logger.info("Sending OTP Request to UIDAI to send OTP on User Registered Mobile Number.");		
		try {
			String content_type= "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 otpXML= new OTPClient().getOTPXML(otpModel, otpProperties, reqTimeStamp);
			String signedXML= DocSigner.signXML(otpXML, true, keyEntry);
			if (this.digilockerProps.isExceptionEnabled()) {
				logger.info("OTP Request XML is:- " + otpXML);
			}
			
			Utilities.checkProxy(digilockerProps.isProxy(), digilockerProps.getProxyHost(), digilockerProps.getProxyPort());
			String otpStringResponse= new PostData().excutePostXml(uidaiProps.getUidaiServiceUrl(), signedXML, content_type);			
			OTPResponse otpResponse= (null!= otpStringResponse) && (!"".equals(otpStringResponse)) ? OTPResponse.buildStringToOTPObject(otpStringResponse): new OTPResponse();			
			otpResponse.setXmlResp(otpStringResponse);			
			
			if (this.digilockerProps.isExceptionEnabled()) {
				logger.info("OTP Response XML is:- " + otpStringResponse);
			}
			
			if (otpResponse.getRet().toLowerCase().equalsIgnoreCase("y".toLowerCase())) {
				logger.info("OTP sent successfully to user mobile and email id, for more details please see the log.");
			} else {
				for (Entry<String, String> entry : uidaiErrors.getErrorMap().entrySet()) {
		            if (entry.getKey().trim().equals(otpResponse.getErr().trim())) {
		            	otpResponse.setMsg(entry.getValue().trim());		            				                
		            }
		        }
				logger.info("OTP sent failed due to " + otpResponse.getMsg() + ", for more details please see the log.");
			}			
		    return otpResponse;	
		}catch (RuntimeException e) {
			logger.info("Runtime exception in OTPClient.sendOTPRequestToUID:- " +e.getMessage());
			throw e;
		} catch (Exception e) {
			logger.info("Exception in OTPClient.sendOTPRequestToUID:- " +e.getMessage());
			throw e;
		}
	}
	
	private String getOTPXML(OTP otpBean, OTPProperties otpProperties1, String reqTimeStamp)  throws RuntimeException, Exception {
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document document = docBuilder.newDocument();
			Element rootElement = document.createElement("Otp");
			Attr uidAttr = document.createAttribute("uid");
			uidAttr.setValue(otpBean.getAadhaarNumber());
			rootElement.setAttributeNode(uidAttr);
			
			Attr acAttr = document.createAttribute("ac");
			acAttr.setValue(otpProperties1.getOtpACVal());
			rootElement.setAttributeNode(acAttr);
			
			Attr saAttr = document.createAttribute("sa");
			saAttr.setValue(otpProperties1.getOtpSAVal());
			rootElement.setAttributeNode(saAttr);
			
			Attr verAttr = document.createAttribute("ver");
			verAttr.setValue(otpProperties1.getOtpVersionVal());
			rootElement.setAttributeNode(verAttr);
			
			Attr txnAttr = document.createAttribute("txn");
			txnAttr.setValue(otpBean.getUniqueReqId());
			rootElement.setAttributeNode(txnAttr);
			
			Attr tsAttr = document.createAttribute("ts");
			tsAttr.setValue(reqTimeStamp);
			rootElement.setAttributeNode(tsAttr);
			
			Attr lkAttr = document.createAttribute("lk");
			lkAttr.setValue(otpProperties1.getOtpLKVal());
			rootElement.setAttributeNode(lkAttr);
			
			Attr typeAttr = document.createAttribute("type");
			typeAttr.setValue(otpBean.getType());
			rootElement.setAttributeNode(typeAttr);
		      
			Element optsElement = document.createElement("Opts");
			optsElement.setAttribute("ch", otpProperties1.getOptsCHMobVal());
			rootElement.appendChild(optsElement);
			
			document.appendChild(rootElement);
			
			return Utilities.convertDocumentToString(document);
		}catch (RuntimeException e) {
			logger.error("Runtime Exception in creating OTP XML:- " + e.getMessage());
			throw e;
		}catch (Exception e) {
			logger.error("Exception in creating OTP XML:- " + e.getMessage());
			throw e;
		}
	}
}
