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

import java.net.InetAddress;
import java.util.Base64;
import java.util.Date;

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.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.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({ "/api" })
public class EKYCController1 {

	@Autowired Validator validator;
	@Autowired MessageSendTaskExecutor taskExecutor;
	@Autowired UidaiErrors uidaiErrors;

	private static final Logger logger = LoggerFactory.getLogger(EKYCController1.class);
	
	@SuppressWarnings("deprecation")
	@PostMapping(value = { "/getkyc" }, produces = { "application/json;charset=UTF-8" })
	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.0;
		double resTime = 0.0;
		String serverIP = "";
		
		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();
		
		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 = InetAddress.getLocalHost().getHostAddress();
			
			final JSONObject jsonObject = new JSONObject();
			
			reqTimeStamp = this.validator.getCurrentDateTimeISOFormat();
			
			this.validator.validateToken(token);
			this.validator.validateUID(uid, type);
			this.validator.validateOtp(otp, fpEnabled);
			
			uniquereqid = this.validator.generateTransactionId(uniquereqid, uid, authtype);
			authtype = this.validator.setAuthTypeForEkyc(authtype);
			consent = this.validator.setResidentialConsent(consent);
			
			//final String localApiKey = this.validator.createAPIKey(this.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 = (double) System.currentTimeMillis();
			String res= "";
			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 = (double) System.currentTimeMillis();
			ekyc.setAvgResTime((resTime - reqTime) / 1000.0);
			
			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("Aadhaar number which response will be captured:-----------" +tempString);
								ekyc.setResponse(ekycRespXML);											
							}
						}
					}
				}
			} else if (properties.isAllResponseCaptured()) {
				ekyc.setResponse(ekycRespXML);					
			} else {
				ekyc.setResponse("Blank Res");
			}
			
			JSONObject jRespObj = (ekycRespXML != null && !"".equals(ekycRespXML)) ? XML.toJSONObject(ekycRespXML) : null;
			String ret = "n";
			String ttl= "";
			JSONObject respObj = new JSONObject();

			try {
				respObj = ((jRespObj != null) ? (jRespObj.has("KycRes") ? jRespObj.getJSONObject("KycRes") : jRespObj.getJSONObject("Resp")) : null);
				ret = ((respObj != null) ? (respObj.has("ret") ? String.valueOf(respObj.get("ret")) : "n") : null);
				ttl = (null != respObj) ? respObj.has("ttl") ? String.valueOf(respObj.get("ttl")) : "" : "";
			} catch (Exception e4) {
				respObj = null;
				ret = "n";
				ttl = (null != respObj) ? respObj.has("ttl") ? String.valueOf(respObj.get("ttl")) : "" : "";
			}

			String msg = "";
			if (null == respObj) {
				logger.error("EKYC using otp auth 2.5 process failed due to null or blank response from server.");
				msg = "EKYC using otp auth 2.5 process failed due to null or blank response from server.";
				status = false;
				ekyc.setErrCode("4002");
				ekyc.setErrMsg(msg);
				ekyc.setStatus(status);
				ekyc.setUidToken("");
				jsonObject.put("code", 4002);
				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()) {
					this.taskExecutor.executeTask(ekyc.toJSONObject(), "C", "ekyc_logs", "logs");
				}
				return new ResponseEntity<>(jsonObject.toString(), HttpStatus.NOT_FOUND);
			}

			if ("n".equalsIgnoreCase(ret)) {
				try {
					KycResponse kycFailedResponse= new KycResponse();
					try {
						kycFailedResponse = KycResponse.buildXMLToKycResponse(ekycRespXML);
						kycFailedResponse.setXmlResp(ekycRespXML);
					} catch (Exception e) {

					}
					logger.error("EKYC using otp auth 2.5 process failed due to code:- " + kycFailedResponse.getErr() + " for more details please see the log.");
					
					if (kycFailedResponse.getErr().equals("1200") || kycFailedResponse.getErr().equals("1201") || kycFailedResponse.getErr().equals("1202") || kycFailedResponse.getErr().equals("1203") || kycFailedResponse.getErr().equals("1204") || kycFailedResponse.getErr().equals("1205")) {
						jsonObject.put("code", kycFailedResponse.getErr());
						msg = "Some technical error occured.";
					} else if("K-100".equalsIgnoreCase(kycFailedResponse.getErr())) {
						jsonObject.put("code", 101);
						msg = "Your Authentication Failed.(#" +kycFailedResponse.getErr()+")";
					} else {
						jsonObject.put("code", kycFailedResponse.getErr());
						msg = "Some technical error occured.";
					}
					uidToken = kycFailedResponse.getUidData().getTkn();
					ekyc.setUidToken(uidToken);
					ekyc.setErrCode(kycFailedResponse.getErr());
					ekyc.setErrMsg(msg);
					ekyc.setStatus(status);					
				} catch (Exception e) {
					jsonObject.put("code", 4001);
					msg = e.getMessage();
					final KycFailedResponse kycFailedResponse2 = KycFailedResponse.buildXMLToKycResponse(ekycRespXML);
					kycFailedResponse2.setXmlResp(ekycRespXML);
					ekyc.setUidToken("");
					ekyc.setErrCode(kycFailedResponse2.getErr());
					ekyc.setResponse(ekycRespXML);
					ekyc.setErrMsg(msg);
					ekyc.setStatus(status);
				}
				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()) {
					this.taskExecutor.executeTask(ekyc.toJSONObject(), "C", "ekyc_logs", "logs");
				}
				return new ResponseEntity<>(jsonObject.toString(), HttpStatus.EXPECTATION_FAILED);
			} else {
				EKYCController1.logger.info("EKYC using otp auth 2.5 process successfully completed.");
				msg = "Your Authentication is Successful.";
				status = true;
				final 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()) {
					this.taskExecutor.executeTask(ekyc.toJSONObject(), "C", "ekyc_logs", "logs");
				}
				return new ResponseEntity<>(jsonObject.toString(), HttpStatus.OK);
			}

		} catch (RuntimeException e2) {
			if (properties.isExceptionEnabled()) {
				e2.printStackTrace();
			}
			EKYCController1.logger.error("Runtime Exception in EKYC home:- " + e2.getLocalizedMessage());
			
			
			final JSONObject jsonObject2 = new JSONObject();
			jsonObject2.put("code", 102);
			jsonObject2.put("status", false);
			jsonObject2.put("access_token", token);
			jsonObject2.put("transaction_id", uniquereqid);
			jsonObject2.put("uid_token", "");
			jsonObject2.put("msg", e2.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.setStatus(false);
			ekyc.setResponse(ekycRespXML);
			ekyc.setAvgResTime(0.0);
			ekyc.setErrCode("RUNTIME EXCEPTION");
			ekyc.setErrMsg(e2.getLocalizedMessage());
			if (properties.isMsgqueueEnabled()) {
				this.taskExecutor.executeTask(ekyc.toJSONObject(), "C", "ekyc_logs", "logs");
			}			
			return new ResponseEntity<>(jsonObject2.toString(), HttpStatus.METHOD_FAILURE);
		} catch (Exception e3) {
			if (properties.isExceptionEnabled()) {
				e3.printStackTrace();
			}
			EKYCController1.logger.error("Main Exception in EKYC home:- " + e3.getLocalizedMessage());
			final JSONObject jsonObject2 = new JSONObject();
			jsonObject2.put("code", 102);
			jsonObject2.put("status", false);
			jsonObject2.put("access_token", token);
			jsonObject2.put("transaction_id", uniquereqid);
			jsonObject2.put("uid_token", "");
			jsonObject2.put("msg", e3.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.setStatus(false);
			ekyc.setResponse(ekycRespXML);
			ekyc.setAvgResTime(0.0);
			ekyc.setErrCode("RUNTIME EXCEPTION");
			ekyc.setErrMsg(e3.getLocalizedMessage());
			if (properties.isMsgqueueEnabled()) {
				this.taskExecutor.executeTask(ekyc.toJSONObject(), "C", "ekyc_logs", "logs");
			}			
			return new ResponseEntity<>(jsonObject2.toString(), HttpStatus.METHOD_FAILURE);
		}
	}

	@GetMapping(value = { "/getkyc" }, produces = { "application/json;charset=UTF-8" })
	public ResponseEntity<String> ekycHome() {
		final 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<>(jsonObject.toString(), HttpStatus.BAD_REQUEST);
	}
}