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

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

import org.json.JSONException;
import org.json.JSONObject;
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.OTPCollection;
import in.gov.digilocker.uidai.logs.modal.OTP;
import in.gov.digilocker.uidai.logs.sender.MessageSendTaskExecutor;
import in.gov.digilocker.uidai.services.client.OTPClient;
import in.gov.digilocker.uidai.services.properties.UidaiErrors;
import in.gov.digilocker.uidai.services.xmlresponse.OTPResponse;
import in.gov.digilocker.uidai.web.exceptions.KeyMismatchException;
import in.gov.digilocker.uidai.web.properties.DigilockerProperties;
import in.gov.digilocker.uidai.web.validator.Validator;

@RestController
@RequestMapping("/api")
public class OTPController {
	
	@Autowired Validator validator;
	@Autowired DigilockerProperties properties;	
	@Autowired OTPClient otpClient;
	@Autowired MessageSendTaskExecutor taskExecutor;
	@Autowired UidaiErrors uidaiErrors;
	
	private static final Logger logger= LoggerFactory.getLogger(OTPController.class);	
	
	@SuppressWarnings("deprecation")
	@PostMapping(value="/getotp/v2", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<String> getOtp(@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="aadhaar_token", required=true)String token,
			@RequestParam(name="authtype", required=false, defaultValue="otpauth")String authtype,
			@RequestParam(name="consent", required=false, defaultValue="N")String rc,			
			@RequestParam(name="key", required=false)String clientkey) {		
		OTP otpModel= new OTP();
		String reqTimeStamp="";
		String[] infoArray= null;
		String maskedMobile="";
		String maskedEmail="";
		double reqTime=0.0;
		double resTime=0.0;
		String serverIP= "";
		try {
			serverIP= Inet4Address.getLocalHost().getHostAddress();
			validator.validateToken(token);
			validator.validateUID(uid, type);
			authtype= validator.setAuthTypeForOTP(authtype);
			rc= validator.setResidentialConsent(rc);
			reqTimeStamp= validator.getCurrentDateTimeISOFormat();
			uniquereqid= validator.generateTransactionId(uniquereqid, uid, authtype);
			
			String localApiKey= validator.createAPIKey(properties.getApiKeyDateFormat(), token);
			if(properties.isExceptionEnabled()) {
				logger.info("API Keys is:- " +localApiKey);
			}			
			clientkey= "TEST";
			if(!"TEST".equals(clientkey)) {
				throw new KeyMismatchException("Invalid client key."); 
			}
			otpModel.setUniqueReqId(uniquereqid);
			otpModel.setAadhaarNumber(uid);
			otpModel.setType(type);
			otpModel.setAuthType(authtype);
			otpModel.setConsent(rc);
			otpModel.setServerIP(serverIP);
			
			reqTime= System.currentTimeMillis();			
			OTPResponse otpResponse= otpClient.sendOTPRequestToUID(otpModel, reqTimeStamp);
			resTime= System.currentTimeMillis();
			infoArray = (null!= otpResponse) && ("y".equalsIgnoreCase(otpResponse.getRet())) ? otpResponse.getInfo().split(",") : null;			
			
			JSONObject finalJSONResponse= new JSONObject();
			
			boolean status = false; String msg = ""; String code= "";
			
			otpModel.setAvgResTime((resTime - reqTime)/ 1000.0D);
			
			if ("y".toLowerCase().equals(otpResponse.getRet().toLowerCase())){
				status= true;
				msg= "OTP Sent Successfully.";				
		        maskedMobile = infoArray[6];
		        maskedEmail = infoArray[7].substring(0, infoArray[7].length() - 1);
		        
		        finalJSONResponse.put("uid_token", "");
		        finalJSONResponse.put("masked_mobile", maskedMobile);
		        finalJSONResponse.put("masked_email", maskedEmail);		        
		        finalJSONResponse.put("access_token", token);		        
		        finalJSONResponse.put("transaction_id", otpModel.getUniqueReqId());
		        finalJSONResponse.put("status", status);
		        finalJSONResponse.put("code", otpResponse.getErr());
		        finalJSONResponse.put("msg", msg);
		        
		        otpModel.setUidToken("");
		        otpModel.setErrCode("");
		        otpModel.setErrMsg("");
		        otpModel.setResponse(otpResponse.getXmlResp());
		        otpModel.setStatus(status);
		        
		        if (this.properties.isMsgqueueEnabled()) {
		        	taskExecutor.executeTask(otpModel.toJSONObject(), "C", OTPCollection.OTP_COLLECTION_NAME, OTPCollection.OTP_LOG_DATABASE);
		        }
		        
				return new ResponseEntity<String>(finalJSONResponse.toString(), HttpStatus.OK);		        
			}
			
			status= false;
			maskedMobile= "";  maskedEmail= "";
			for (Entry<String, String> entry : uidaiErrors.getErrorMap().entrySet()) {
				if (entry.getKey().equals(otpResponse.getErr())) {
					code = otpResponse.getErr();
					msg = entry.getValue();
				}
			}			
			
			finalJSONResponse.put("transaction_id", otpModel.getUniqueReqId());
			finalJSONResponse.put("masked_mobile", maskedMobile);
	        finalJSONResponse.put("masked_email", maskedEmail);
	        finalJSONResponse.put("access_token", token);
	        finalJSONResponse.put("status", status);		        
	        finalJSONResponse.put("uid_token", "");
			finalJSONResponse.put("code", code);
	        finalJSONResponse.put("msg", msg);
	        
	        otpModel.setUidToken("");
	        otpModel.setResponse(otpResponse.getXmlResp());
	        otpModel.setStatus(status);		        
	        otpModel.setErrCode(code);
	        otpModel.setErrMsg(msg);
	        
	        if (this.properties.isMsgqueueEnabled()) {
	        	taskExecutor.executeTask(otpModel.toJSONObject(), "C", OTPCollection.OTP_COLLECTION_NAME, OTPCollection.OTP_LOG_DATABASE);
	        }
	        
			return new ResponseEntity<String>(finalJSONResponse.toString(), HttpStatus.EXPECTATION_FAILED);			
				
		} catch (RuntimeException e) {
			
			logger.error("Runtime Exception in sending OTP:- " + e.getMessage());
			boolean status= false;
			
			JSONObject jsonObject= new JSONObject();
			jsonObject.put("status", status);
			jsonObject.put("access_token", token);
			jsonObject.put("code", "RUNTIME-102");
			jsonObject.put("msg", e.getMessage());
			jsonObject.put("transaction_id", otpModel.getUniqueReqId());
			jsonObject.put("uid_token", "");
			jsonObject.put("response", "");
			
			otpModel.setUniqueReqId(uniquereqid);
			otpModel.setUidToken("");
			otpModel.setAadhaarNumber(uid);
			otpModel.setType(type);
			otpModel.setAuthType(authtype);
			otpModel.setConsent(rc);
			otpModel.setStatus(status);
			otpModel.setResponse("");
			otpModel.setAvgResTime(0.0);			
			otpModel.setErrCode("RUNTIME-102");
			otpModel.setErrMsg(e.getMessage());			
			
			if (this.properties.isMsgqueueEnabled()) {
				taskExecutor.executeTask(otpModel.toJSONObject(), "C", OTPCollection.OTP_COLLECTION_NAME, OTPCollection.OTP_LOG_DATABASE);			
			}
			
			return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.METHOD_FAILURE);
		} catch (Exception e) {
			e.printStackTrace();
			
			logger.error("Main Exception in sending OTP:- " + e.getMessage());
			
			boolean status= false;
			
			JSONObject jsonObject= new JSONObject();
			jsonObject.put("status", status);
			jsonObject.put("code", "MAIN-102");
			jsonObject.put("msg", e.getMessage());
			jsonObject.put("transaction_id", otpModel.getUniqueReqId());
			jsonObject.put("uid_token", "");
			jsonObject.put("access_token", token);
			jsonObject.put("response", "");
			
			otpModel.setUniqueReqId(uniquereqid);
			otpModel.setUidToken("");
			otpModel.setAadhaarNumber(uid);
			otpModel.setType(type);
			otpModel.setAuthType(authtype);
			otpModel.setConsent(rc);
			otpModel.setStatus(status);
			otpModel.setResponse("");
			otpModel.setAvgResTime(0.0);
			otpModel.setErrCode("MAIN-102");
			otpModel.setErrMsg(e.getMessage());			
			
			if (this.properties.isMsgqueueEnabled()) {
				taskExecutor.executeTask(otpModel.toJSONObject(), "C", OTPCollection.OTP_COLLECTION_NAME, OTPCollection.OTP_LOG_DATABASE);			
			}
			
			return new ResponseEntity<String>(jsonObject.toString(), HttpStatus.METHOD_FAILURE);
		}
	}	
	
	@GetMapping(value="/getotp/v2", produces=MediaType.APPLICATION_JSON_VALUE)
	public String otpHome() {
		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 jsonObject.toString();
	}
}