package in.gov.digilocker.uidai.web.controller.v2;

import java.net.Inet4Address;
import java.util.Base64;
import java.util.Date;
import java.util.Map.Entry;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import in.gov.digilocker.uidai.logs.constants.EKycCollection;
import in.gov.digilocker.uidai.logs.fpmodal.BiomatricData;
import in.gov.digilocker.uidai.logs.modal.EKYC;
import in.gov.digilocker.uidai.logs.sender.MessageSendTaskExecutor;
import in.gov.digilocker.uidai.services.client.AuthClient;
import in.gov.digilocker.uidai.services.client.EKYCClient;
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.properties.UidaiErrors;
import in.gov.digilocker.uidai.services.xmlresponse.KycFailedResponse;
import in.gov.digilocker.uidai.services.xmlresponse.KycResponse;
import in.gov.digilocker.uidai.web.exceptions.KeyMismatchException;
import in.gov.digilocker.uidai.web.properties.DigilockerProperties;
import in.gov.digilocker.uidai.web.validator.Validator;
import in.gov.digilocker.uidai.web.validator.WriteStringToFile;

@RestController
@RequestMapping(value = "/api")
public class EKYCController {
	
	@Autowired Validator validator;
	@Autowired MessageSendTaskExecutor taskExecutor;
	@Autowired UidaiErrors uidaiErrors;
	
	private static final Logger logger = LoggerFactory.getLogger(EKYCController.class);
	@SuppressWarnings("deprecation")
	@PostMapping(value = "/getkyc/v2", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<String> getKyc(
			@RequestParam(name = "transaction_id", required = false) String uniquereqid,
			@RequestParam(name = "aadhaarNumber", required = true) String uid,
			@RequestParam(name = "type", required = false, defaultValue = "A") String type,
			@RequestParam(name = "OTP", required = true) String otp,
			@RequestParam(name = "fpenabled", required = false, defaultValue = "N") String fpEnabled,
			@RequestParam(name = "aadhaar_token", required = true) String token,
			@RequestParam(name = "authtype", required = false, defaultValue = "kyc") String authtype,
			@RequestParam(name = "consent", required = true, defaultValue = "N") String consent,
			@RequestParam(name = "pdf", required = false, defaultValue = "N") String pdf,
			@RequestParam(name = "xml", required = false, defaultValue = "Y") String xml,
			@RequestParam(name = "clientkey", required = false, defaultValue = "TEST") String clientkey) {
		
		String encodedXMLResp= "";
		String ekycRespXML= "";
		String reqTimeStamp = "";
		String uidToken = "";
		double reqTime = 0.0D;
		double resTime = 0.0D;
		
		EKYC ekyc = new EKYC();
		DigilockerProperties properties= new DigilockerProperties();	
		EKYCClient ekycClient= new EKYCClient();
		UIDAIProps uidaiProps= new UIDAIProps();
		EKYCProperties ekycProps= new EKYCProperties();
		AuthClient authClient= new AuthClient();
		OTPAuthProperties authProps= new OTPAuthProperties();
		
		String serverIP = "";
		JSONObject resObj= null;
		try {
			if(properties.isExceptionEnabled()) {
				logger.info("aadhaarNumber is:---" +uid);
				logger.info("transaction_id is:---" +uniquereqid);
				logger.info("type is:---" +type);
				logger.info("OTP is:---" +otp);
				logger.info("fpenabled is:---" +fpEnabled);
				logger.info("aadhaar_token is:---" +token);
				logger.info("authtype  is:---" +authtype);
				logger.info("consent is:---" +consent);
				logger.info("pdf is:---" +pdf);
				logger.info("xml is:---" +xml);
				logger.info("clientkey is:---" +clientkey);
			}			
			
			serverIP = Inet4Address.getLocalHost().getHostAddress();
			JSONObject jsonObject = new JSONObject();
			reqTimeStamp = validator.getCurrentDateTimeISOFormat();
			validator.validateToken(token);
			validator.validateUID(uid, type);
			validator.validateOtp(otp, fpEnabled);
			
			uniquereqid = validator.generateTransactionId(uniquereqid, uid, authtype);
			authtype = validator.setAuthTypeForEkyc(authtype);
			consent = validator.setResidentialConsent(consent);
			
			//String localApiKey = validator.createAPIKey(properties.getApiKeyDateFormat(), token);
			
			if (!"TEST".equals(clientkey)) {
				throw new KeyMismatchException("Invalid client key.");
			}
			
			JSONObject reqObject= new JSONObject();
			reqObject.put("tid", uniquereqid);
			reqObject.put("type", type);
			reqObject.put("otp", otp);
			reqObject.put("fpenabled", fpEnabled);
			reqObject.put("aadhaar_token", token);
			reqObject.put("auth_type", authtype);
			reqObject.put("consent", consent);
			reqObject.put("is_pdf", pdf);
			reqObject.put("is_xml", xml);
			
			
			ekyc.setClientRequestData(reqObject.toString());
			
			ekyc.setUniqueReqId(uniquereqid);
			ekyc.setAadhaarNumber(uid);
			ekyc.setType(type);			
			ekyc.setFpEnabled(fpEnabled);
			ekyc.setAuthType(authtype);
			ekyc.setConsent(consent);
			ekyc.setServerIP(serverIP);
			ekyc.setPdf(pdf.trim());
			ekyc.setXml(xml.trim());
			
			boolean status = false;
			reqTime = System.currentTimeMillis();
			
			String res= "";
			String ttl= "";
				
			if("Y".equalsIgnoreCase(fpEnabled)) {
				try {
					String decodeOtp= new String(Base64.getDecoder().decode(otp.replaceAll("\\Q**\\E", "+")));
					ekyc.setOtp(decodeOtp);
					BiomatricData biomatricResponse = BiomatricData.buildXMLToBioMatricData(ekyc.getOtp());
					
					resObj= ekycClient.verifyEkycAadhaarUsingFingerPrint(ekycClient, uidaiProps, properties, ekycProps, authClient, authProps, ekyc, biomatricResponse, reqTimeStamp);
					res= null!= resObj && resObj.has("response_data") && !(resObj.isNull("response_data")) ? resObj.getString("response_data") : "";					
				
				} catch (Exception e) {
					
					if (properties.isExceptionEnabled()) {
						e.printStackTrace();
					}
				}
			} else {
				
				ekyc.setOtp(otp);
				resObj= ekycClient.verifyEkycAadhaarUsingOtp(ekycClient, uidaiProps, properties, ekycProps, authClient, authProps, ekyc,  reqTimeStamp);				
				res= null!= resObj && resObj.has("response_data") && !(resObj.isNull("response_data")) ? resObj.getString("response_data") : "";
			
			}
			
			try {
				ekycRespXML= res.replace("\\", "");
			} catch (Exception e) {
				ekycRespXML = res;
			}
			
			ekyc.setRequestData(null!= resObj && resObj.has("request_data") && !(resObj.isNull("request_data")) ? resObj.getString("request_data") : "");
			
			resTime = System.currentTimeMillis();
			
			ekyc.setAvgResTime((resTime - reqTime) / 1000D);
			
			if(properties.isResponseCapturedUsingList()) {
				String delimeter= ",";
				if(null!= properties.getAadhaarList() && !"".equals(properties.getAadhaarList())) {
					String aadhaarList= properties.getAadhaarList().trim();
					if(aadhaarList.contains(delimeter)) {
						String [] tempArray= aadhaarList.split(delimeter);
						for (String tempString : tempArray) {
							System.out.println(tempString);
							if(uid.trim().equalsIgnoreCase(tempString)) {
								System.out.println("Error in aadhaar number is:-----------" +tempString);
								ekyc.setResponse(ekycRespXML);											
							}
						}
					}
				}
			} else if (properties.isAllResponseCaptured()) {
				ekyc.setResponse(ekycRespXML);					
			} else {
				ekyc.setResponse("Blank Res");
			}			
			
			JSONObject jRespObj = (null != ekycRespXML) && (!"".equals(ekycRespXML)) ? XML.toJSONObject(ekycRespXML) : null;
			String ret = "n";
			
			JSONObject respObj = new JSONObject();
			try {
				respObj = (null != jRespObj) ? jRespObj.has("KycRes") ? jRespObj.getJSONObject("KycRes") : jRespObj.getJSONObject("Resp") : null;
				ret = (null != respObj) ? respObj.has("ret") ? String.valueOf(respObj.get("ret")) : "n" : null;
				ttl = (null != respObj) ? respObj.has("ttl") ? String.valueOf(respObj.get("ttl")) : "" : "";
			} catch (Exception e) {
				respObj = null;
				ttl = (null != respObj) ? respObj.has("ttl") ? String.valueOf(respObj.get("ttl")) : "" : "";
				ret = "n";
			}
			String msg = "";
			String code = "";
			
			if (null != respObj && "n".equalsIgnoreCase(ret)) {
				try {					
					KycResponse kycFailedResponse = KycResponse.buildXMLToKycResponse(ekycRespXML);
					kycFailedResponse.setXmlResp(ekycRespXML);
					
					for (Entry<String, String> entry : uidaiErrors.getErrorMap().entrySet()) {
						if (entry.getKey().equals(kycFailedResponse.getErr())) {
							code = kycFailedResponse.getErr();
							jsonObject.put("code", code);
							msg = entry.getValue();
						}
					}					
					uidToken = kycFailedResponse.getUidData().getTkn();					
					ekyc.setUidToken(uidToken);
					ekyc.setErrCode(code);
					ekyc.setErrMsg(msg);
					ekyc.setStatus(status);
				} catch (Exception e) {
					msg = e.getMessage();
					KycFailedResponse kycFailedResponse = KycFailedResponse.buildXMLToKycResponse(ekycRespXML);
					kycFailedResponse.setXmlResp(ekycRespXML);
					ekyc.setUidToken(uidToken);					
					ekyc.setErrCode(kycFailedResponse.getErr());
					ekyc.setErrMsg(msg);
					ekyc.setStatus(status);
					jsonObject.put("code", kycFailedResponse.getErr());
				}
				jsonObject.put("msg", msg);
				jsonObject.put("status", status);
				jsonObject.put("access_token", token);
				jsonObject.put("uid_token", uidToken);
				jsonObject.put("ttl_ekyc", ttl);
				jsonObject.put("transaction_id", ekyc.getUniqueReqId());
				
				if (properties.isMsgqueueEnabled()) {
					taskExecutor.executeTask(ekyc.toJSONObject(), "C", EKycCollection.EKYC_COLLECTION_NAME, EKycCollection.EKYC_LOG_DATABASE);
				}				
				return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.EXPECTATION_FAILED);
			} else if (null != respObj && "y".equalsIgnoreCase(ret)) {
				logger.info("EKYC using otp auth 2.5 process successfully completed.");
				msg = "Your Authentication is Successful.";
				status = true;
				KycResponse kycResponse = KycResponse.buildXMLToKycResponse(ekycRespXML);
				kycResponse.setXmlResp(ekycRespXML);
				uidToken = kycResponse.getUidData().getTkn();
				ekyc.setUidToken(uidToken);
				ekyc.setErrCode("");
				ekyc.setErrMsg("");
				ekyc.setStatus(status);
				jsonObject.put("ttl_ekyc", ttl);
				jsonObject.put("code", "");
				jsonObject.put("status", status);
				jsonObject.put("access_token", token);
				jsonObject.put("msg", "Your Authentication is Successful.");
				jsonObject.put("uid_token", uidToken);
				jsonObject.put("transaction_id", ekyc.getUniqueReqId());
				jsonObject.put("AadhaarNo", kycResponse.getUidData().getUid());
				jsonObject.put("residentName", kycResponse.getUidData().getPoi().getName().trim());
				jsonObject.put("dateOfBirth", kycResponse.getUidData().getPoi().getDob().trim());
				jsonObject.put("gender", kycResponse.getUidData().getPoi().getGender().trim());
				jsonObject.put("emailId", kycResponse.getUidData().getPoi().getEmail().trim());
				jsonObject.put("phone", kycResponse.getUidData().getPoi().getPhone().trim());
				jsonObject.put("careOf", kycResponse.getUidData().getPoa().getCo().trim());
				jsonObject.put("houseNumber", kycResponse.getUidData().getPoa().getHouse().trim());
				jsonObject.put("street", kycResponse.getUidData().getPoa().getStreet().trim());
				jsonObject.put("vtc", kycResponse.getUidData().getPoa().getVtc().trim());
				jsonObject.put("locality", kycResponse.getUidData().getPoa().getLoc().trim());
				jsonObject.put("landmark", kycResponse.getUidData().getPoa().getLm().trim());
				jsonObject.put("country", kycResponse.getUidData().getPoa().getCountry().trim());
				jsonObject.put("postOffice", kycResponse.getUidData().getPoa().getPo().trim());
				jsonObject.put("subDistrict", kycResponse.getUidData().getPoa().getSubdist().trim());
				jsonObject.put("district", kycResponse.getUidData().getPoa().getDist().trim());
				jsonObject.put("state", kycResponse.getUidData().getPoa().getState().trim());
				jsonObject.put("pincode", kycResponse.getUidData().getPoa().getPc().trim());
				jsonObject.put("language", kycResponse.getUidData().getLData().getLang().trim());
				jsonObject.put("residentNameLocal", kycResponse.getUidData().getLData().getName().trim());
				jsonObject.put("careOfLocal", kycResponse.getUidData().getLData().getCo().trim());
				jsonObject.put("houseNumberLocal", kycResponse.getUidData().getLData().getHouse().trim());
				jsonObject.put("streetLocal", kycResponse.getUidData().getLData().getStreet().trim());
				jsonObject.put("vtcLocal", kycResponse.getUidData().getLData().getVtc().trim());
				jsonObject.put("localityLocal", kycResponse.getUidData().getLData().getLoc().trim());
				jsonObject.put("landmarkLocal", kycResponse.getUidData().getLData().getLm().trim());
				jsonObject.put("postOfficeLocal", kycResponse.getUidData().getLData().getPo().trim());
				jsonObject.put("countryLocal", kycResponse.getUidData().getLData().getCountry().trim());
				jsonObject.put("subDistrictLocal", kycResponse.getUidData().getLData().getSubdist().trim());
				jsonObject.put("districtLocal", kycResponse.getUidData().getLData().getDist().trim());
				jsonObject.put("stateLocal", kycResponse.getUidData().getLData().getState().trim());
				jsonObject.put("pincodeLocal", kycResponse.getUidData().getLData().getPc().trim());
				jsonObject.put("photo", kycResponse.getUidData().getPht().trim());
				jsonObject.put("type", kycResponse.getUidData().getPrn().getType().trim());
				if ("Y".equalsIgnoreCase(ekyc.getPdf().toUpperCase())) {
					jsonObject.put("pdf", kycResponse.getUidData().getPrn().getPrnValue().trim());
				}
				if ("Y".equalsIgnoreCase(ekyc.getXml())) {
					encodedXMLResp= Base64.getEncoder().encodeToString(ekycRespXML.getBytes("UTF-8"));
					jsonObject.put("kycXmlRes", encodedXMLResp);
				}
				if (properties.isExceptionEnabled()) { 
                	try {					
    					WriteStringToFile.writeToFile1(encodedXMLResp);
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
                }
				
				if (properties.isMsgqueueEnabled()) {
					taskExecutor.executeTask(ekyc.toJSONObject(), "C", EKycCollection.EKYC_COLLECTION_NAME, EKycCollection.EKYC_LOG_DATABASE);
				}
				
				return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.OK);
				
			} else {
				msg = "EKYC using otp auth 2.5 process failed due to null or blank response from server.";
				status = false;
				ekyc.setErrCode("D-103");
				ekyc.setErrMsg(msg);
				ekyc.setStatus(status);
				ekyc.setUidToken("");
				jsonObject.put("code", "D-103");
				jsonObject.put("msg", msg);
				jsonObject.put("status", status);
				jsonObject.put("access_token", token);
				jsonObject.put("uid_token", "");
				jsonObject.put("transaction_id", ekyc.getUniqueReqId());
				
				if (properties.isMsgqueueEnabled()) {
					taskExecutor.executeTask(ekyc.toJSONObject(), "C", EKycCollection.EKYC_COLLECTION_NAME, EKycCollection.EKYC_LOG_DATABASE);
				}
				
				return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.NOT_FOUND);
			}
		} catch (RuntimeException e) {			
			if (properties.isExceptionEnabled()) {
				logger.error("Runtime Exception in EKYC home:- " + e.getLocalizedMessage());
				e.printStackTrace();
			}
			
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("transaction_id", uniquereqid);
			jsonObject.put("access_token", token);
			jsonObject.put("uid_token", "");
			jsonObject.put("status", false);
			jsonObject.put("code", "D-102");
			jsonObject.put("msg", e.getLocalizedMessage());
			
			ekyc.setRequestData(null!= resObj && resObj.has("request_data") && !(resObj.isNull("request_data")) ? resObj.getString("request_data") : "");			
			ekyc.setUniqueReqId(uniquereqid);
			ekyc.setUidToken("");
			ekyc.setAadhaarNumber(uid);
			ekyc.setType(type);
			ekyc.setOtp(otp);
			ekyc.setAuthType(authtype);
			ekyc.setConsent(consent);
			ekyc.setResponse(ekycRespXML);
			ekyc.setStatus(false);
			ekyc.setAvgResTime(0.0);
			ekyc.setErrCode("D-102");
			ekyc.setErrMsg(e.getLocalizedMessage());
			
			if (properties.isMsgqueueEnabled()) {
				taskExecutor.executeTask(ekyc.toJSONObject(), "C", EKycCollection.EKYC_COLLECTION_NAME, EKycCollection.EKYC_LOG_DATABASE);
			}
			
			return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.METHOD_FAILURE);
		} catch (Exception e) {						
			logger.error("Main Exception in EKYC home:- " + e.getLocalizedMessage());
			e.printStackTrace();
			
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("code", "D-104");
			jsonObject.put("status", false);
			jsonObject.put("access_token", token);
			jsonObject.put("transaction_id", uniquereqid);
			jsonObject.put("uid_token", "");
			jsonObject.put("msg", e.getLocalizedMessage());
			
			ekyc.setRequestData(null!= resObj && resObj.has("request_data") && !(resObj.isNull("request_data")) ? resObj.getString("request_data") : "");
			ekyc.setUniqueReqId(uniquereqid);
			ekyc.setUidToken("");
			ekyc.setAadhaarNumber(uid);
			ekyc.setType(type);
			ekyc.setOtp(otp);
			ekyc.setAuthType(authtype);
			ekyc.setResponse(ekycRespXML);
			ekyc.setConsent(consent);
			ekyc.setStatus(false);
			ekyc.setAvgResTime(0.0);
			ekyc.setErrCode("D-104");
			ekyc.setErrMsg(e.getLocalizedMessage());
			
			if (properties.isMsgqueueEnabled()) {
				taskExecutor.executeTask(ekyc.toJSONObject(), "C", EKycCollection.EKYC_COLLECTION_NAME, EKycCollection.EKYC_LOG_DATABASE);
			}
			
			return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.METHOD_FAILURE);
		}
	}

	@GetMapping(value = "/getkyc/v2", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<String> ekycHome() {
		JSONObject jsonObject = new JSONObject();
		try {
			jsonObject.put("code", -1);
			jsonObject.put("status", false);
			jsonObject.put("response", "Get method not allowed here.");
			jsonObject.put("date", new Date());
		} catch (JSONException e) {
			e.printStackTrace();
			jsonObject.put("code", -1);
			jsonObject.put("status", false);
			jsonObject.put("response", e.getLocalizedMessage());
			jsonObject.put("date", new Date());
		}
		return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.BAD_REQUEST);
	}
}
