package com.bankaudit.rest.process.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.bankaudit.constants.BankAuditConstant;
import com.bankaudit.dto.DataTableResponse;
import com.bankaudit.dto.process.AuditLettersDto;
import com.bankaudit.dto.process.LettersDto;
import com.bankaudit.process.model.AuditLetterUserInputsWrk;
import com.bankaudit.rest.process.service.LettersService;
import com.bankaudit.service.BusinessDateService;
import com.bankaudit.util.BankAuditUtil;
import com.bankaudit.util.ServiceStatus;



@RestController

@RequestMapping("/api/letters")
public class LettersController {
	
	@Autowired
	LettersService lettersService;
	
	@Autowired
	BusinessDateService businessDateService;
	
	static final Logger logger = Logger.getLogger(LettersController.class);
	
	
@RequestMapping(value="/getLettersByAuditId/{legalEntityCode}/{auditTypeCode}/{auditId}/{role}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus getLettersByAuditId(
			@PathVariable("legalEntityCode") Integer legalEntityCode,
			@PathVariable("auditTypeCode") String auditTypeCode,
			@PathVariable("auditId")String auditId,
			@PathVariable("role")String role){
		ServiceStatus serviceStatus=new ServiceStatus();
		
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(auditTypeCode)  && !BankAuditUtil.isEmptyString(auditId)){
			try {
				List<LettersDto> ltrLst=lettersService.getLettersByAuditId(legalEntityCode,auditTypeCode,auditId,role); 
				if(ltrLst!=null){
					serviceStatus.setResult(ltrLst);
					serviceStatus.setStatus("success");
					serviceStatus.setMessage("successfuly retrieved ");
				}else {
					serviceStatus.setStatus("failure");
					serviceStatus.setMessage("No Letters found");
				}				
			} catch (Exception e) {
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure");
				e.printStackTrace();
			}
			
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
				return serviceStatus;
	}
	
	
@RequestMapping(value="/getLetterByAuditIdAndLetterCode/{legalEntityCode}/{auditId}/{letterCode}/{status}/{auditTypeCode}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus getLetterByAuditIdAndLetterCode(
			@PathVariable("legalEntityCode") Integer legalEntityCode,
			@PathVariable("auditId")String auditId,
			@PathVariable("letterCode") String letterCode,
			@PathVariable("status")String status ,
			@PathVariable("auditTypeCode")String auditTypeCode 
			){
		ServiceStatus serviceStatus=new ServiceStatus();
		
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(letterCode)  && !BankAuditUtil.isEmptyString(auditId)){
			try {
				AuditLettersDto adtLtrDto=lettersService.getLetterByAuditIdAndLetterCode(legalEntityCode,auditId,letterCode,status,auditTypeCode); 
				if(adtLtrDto!=null){
					serviceStatus.setResult(adtLtrDto);
					serviceStatus.setStatus("success");
					serviceStatus.setMessage("successfuly retrieved ");
				}else {
					serviceStatus.setStatus("failure");
					serviceStatus.setMessage("No Letters found");
				}				
			} catch (Exception e) {
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure");
				e.printStackTrace();
			}
			
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
				return serviceStatus;
	}
	
	
@RequestMapping(method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus createAuditLetter(@RequestBody AuditLetterUserInputsWrk adtLtrWrk){
		
		ServiceStatus serviceStatus=new ServiceStatus();
		logger.info("createAuditLetter .. "+ adtLtrWrk.getLegalEntityCode() +" :: "+adtLtrWrk.getAuditId() +" :: "+adtLtrWrk.getLetterCode()+" :: "+adtLtrWrk.getStatus());
		if(adtLtrWrk!=null && adtLtrWrk.getLegalEntityCode()!=null && adtLtrWrk.getAuditId()!=null && adtLtrWrk.getLetterCode()!=null
				&& adtLtrWrk.getMaker()!=null && adtLtrWrk.getStatus()!=null){
			try {
				adtLtrWrk.setSysdateTimestamp(new Timestamp(System.currentTimeMillis()));
				adtLtrWrk.setBusinessdateTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(adtLtrWrk.getLegalEntityCode()));
				adtLtrWrk.setMakerTimestamp(adtLtrWrk.getBusinessdateTimestamp());
				
				lettersService.createAuditLetter(adtLtrWrk);
				serviceStatus.setStatus("success");
				serviceStatus.setMessage("successfully created");	
								
			} catch (Exception e) {
				e.printStackTrace();
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure");
				if(e instanceof org.springframework.dao.DataIntegrityViolationException) {
					serviceStatus.setMessage("DATAINTGRTY_VIOLATION");
				}
			}			
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid user payload");
		}		
		return serviceStatus;
	}
	
	
@RequestMapping(method=RequestMethod.PUT,consumes=MediaType.APPLICATION_JSON_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus updateAuditLetter(@RequestBody AuditLetterUserInputsWrk adtLtrWrk) {
		
		ServiceStatus serviceStatus=new ServiceStatus();
		 logger.info("updateAuditLetter .. "+ adtLtrWrk.getLegalEntityCode() +" :: "+adtLtrWrk.getAuditId() +" :: "+adtLtrWrk.getLetterCode()+" :: "+adtLtrWrk.getStatus());
		 if(adtLtrWrk!=null && adtLtrWrk.getLegalEntityCode()!=null && adtLtrWrk.getAuditId()!=null && adtLtrWrk.getLetterCode()!=null
					&& adtLtrWrk.getMaker()!=null && adtLtrWrk.getStatus()!=null){
				try {
					adtLtrWrk.setSysdateTimestamp(new Timestamp(System.currentTimeMillis()));
					adtLtrWrk.setBusinessdateTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(adtLtrWrk.getLegalEntityCode()));
					adtLtrWrk.setMakerTimestamp(adtLtrWrk.getBusinessdateTimestamp());
					
					lettersService.updateAuditLetter(adtLtrWrk);
					serviceStatus.setStatus("success");
					serviceStatus.setMessage("successfully updated");	
									
				} catch (Exception e) {
					e.printStackTrace();
					serviceStatus.setStatus("failure");
					serviceStatus.setMessage("failure");
					if(e instanceof org.springframework.dao.DataIntegrityViolationException) {
						serviceStatus.setMessage("DATAINTGRTY_VIOLATION");
					}
				}			
			}else {
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("invalid user payload");
			}		
			return serviceStatus;
	}
	
	
@RequestMapping(value="/deleteAuditLetterByIdCode/{legalEntityCode}/{auditId}/{letterCode}/{status}",method=RequestMethod.DELETE,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus deleteAuditLetterByIdCode(@PathVariable("legalEntityCode")Integer legalEntityCode,
			@PathVariable("auditId") String auditId,@PathVariable("letterCode") String letterCode,@PathVariable("status") String status){
	ServiceStatus serviceStatus=new ServiceStatus();
		logger.info("Inside deleteAuditLetterByIdCode .."+ legalEntityCode+" ::"+auditId+" ::"+letterCode);
		if(legalEntityCode !=null && !BankAuditUtil.isEmptyString(auditId) && !BankAuditUtil.isEmptyString(letterCode)){
			try {
				lettersService.deleteAuditLetterByIdCode(legalEntityCode, auditId, letterCode, status);
				serviceStatus.setStatus("success");
				serviceStatus.setMessage("Record deleted successfully.");
			} catch (Exception e) {
				serviceStatus.setStatus("failure");
				e.printStackTrace();
				if(e instanceof org.springframework.dao.DataIntegrityViolationException) {
					serviceStatus.setMessage("DATAINTGRTY_VIOLATION");
				}
				serviceStatus.setMessage("failure");
			}
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid payload");
		}
		return serviceStatus;
	}
	
	
@RequestMapping(value="/isAuthAllowed",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus isAuthAllowed(
			@RequestParam("legalEntityCode")String legalEntityCodeStr,
			@RequestParam("auditId") String auditId,
			@RequestParam("letterCode") String letterCode,
			@RequestParam(required=false,value="userId") String userId){
		ServiceStatus serviceStatus=new ServiceStatus();
		
		logger.info("LettersController isAuthAllowed() .."+ legalEntityCodeStr+" :: "+ auditId+" :: "+letterCode); 
		if(legalEntityCodeStr!=null && !BankAuditUtil.isEmptyString(letterCode)  && !BankAuditUtil.isEmptyString(auditId)){
			try {
				Integer legalEntityCode=Integer.parseInt(legalEntityCodeStr);
				boolean isAuthAllowed=lettersService.isAuthAllowed(legalEntityCode,auditId,letterCode,userId); 
				if(isAuthAllowed){
					serviceStatus.setStatus("success");
					serviceStatus.setMessage("Authorization is allowed.");
					serviceStatus.setResult(isAuthAllowed);
				} else {
					serviceStatus.setStatus("success");
					serviceStatus.setMessage("Please follow the sequence of Authorization as Forward Letter -> Recommendary note -> Recommendation ->  Letter of Supervisory Concern");
				}				
			} catch (Exception e) {
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure");
				e.printStackTrace();
			}
			
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
				return serviceStatus;
	}
	
	
	
@RequestMapping(value="/saveLetterPDFByAuditIdAndLetterCode/{legalEntityCode}/{auditId}/{letterCode}/{status}/{auditTypeCode}/{userId}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus saveLetterPDFByAuditIdAndLetterCode(
			@PathVariable("legalEntityCode") Integer legalEntityCode,
			@PathVariable("auditId")String auditId,
			@PathVariable("letterCode") String letterCode,
			@PathVariable("status")String status,
			@PathVariable("auditTypeCode") String auditTypeCode,
			@PathVariable("userId") String userId,
			HttpServletRequest request,      HttpServletResponse response){
		
		ServiceStatus serviceStatus=new ServiceStatus();	
		
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(letterCode)  && !BankAuditUtil.isEmptyString(auditId) 
				&& BankAuditConstant.STATUS_AUTH.equalsIgnoreCase(status)){
		 	
			Map<String, Object> params = new HashMap<String, Object>();	
			String uploadStatus = lettersService.saveLetterPDFByAuditIdAndLetterCode(params, legalEntityCode, auditId, letterCode, status, auditTypeCode,userId);	
			if(BankAuditConstant.SUCCESS.equalsIgnoreCase(uploadStatus)){
				serviceStatus.setStatus("success");
				serviceStatus.setMessage("Letter saved successfully"); 
			}else{
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failed"); 
			}
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
		return serviceStatus;	 
	}
	
	
@RequestMapping(value="/downloadLetterPDFByAuditIdAndLetterCode/{legalEntityCode}/{auditId}/{letterCode}/{status}/{auditTypeCode}/{userId}",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	void downloadLetterPDFByAuditIdAndLetterCode(
			@PathVariable("legalEntityCode") Integer legalEntityCode,
			@PathVariable("auditId")String auditId,
			@PathVariable("letterCode") String letterCode, 
			@PathVariable("status") String status,
			@PathVariable("auditTypeCode") String auditTypeCode,
			@PathVariable("userId") String userId, 
			HttpServletRequest request,      HttpServletResponse response) throws IOException{
		
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(letterCode)  && !BankAuditUtil.isEmptyString(auditId)){
			String uploadPath ="";
			if(BankAuditConstant.STATUS_AUTH.equalsIgnoreCase(status)){
				uploadPath = lettersService.getDocReferencePath(legalEntityCode, auditId, letterCode, auditTypeCode);
			}else if(BankAuditConstant.STATUS_UNAUTH.equalsIgnoreCase(status)){
				Map<String, Object> params = new HashMap<String, Object>();
				uploadPath = lettersService.saveLetterPDFByAuditIdAndLetterCode(params, legalEntityCode, auditId, letterCode, status, auditTypeCode, userId);
			}
			if(uploadPath!=null){
		    	 File file=new File(uploadPath);
		    	 FileInputStream inputStream = new FileInputStream(file); 		    	    
				 String mimeType ="application/pdf";  						 
	             response.setContentType(mimeType); 
	             String headerKey = "Content-Disposition";
	             String headerValue = String.format("attachment; filename=\"%s\"",file.getName());
	             response.setHeader(headerKey, headerValue); 
	             OutputStream outStream = response.getOutputStream();
	            
	             byte[] buffer = new byte[4096*4096]; // 4096-> bufferSize
	             int bytesRead = -1;
	       
	             while ((bytesRead = inputStream.read(buffer)) != -1) {
	                 outStream.write(buffer, 0, bytesRead);
	             }
	             inputStream.close();
	             outStream.close();                
	    	}else {
				 response.getWriter().print("Letter not exist");
			}		 
		}else {
			response.getWriter().print("Letter not exist");
		}				 
	}
	
	
@RequestMapping(value = "/getLetterForReviewer", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	DataTableResponse getLetterForReviewer(
			@RequestParam("draw") String drawStr,
			@RequestParam("length") String length,
			@RequestParam("start") String start,
			@RequestParam("search[value]") String search,
			@RequestParam("order[0][column]") String orderColumnStr,
			@RequestParam("order[0][dir]") String orderDirection,
			@RequestParam("legalEntityCode")String legalEntityCodeStr,
			@RequestParam("userId")String userId,
			@RequestParam("role")String role,
			@RequestParam("userUnitType")String userUnitType,
			@RequestParam(required = false, value = "financialYear") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate financialYear,
			@RequestParam(required = false, value = "auditTypeCode") String auditTypeCode){

		DataTableResponse dataTableResponse = null;
		logger.info("legalEntityCode:: "+legalEntityCodeStr +" userId:: "+ userId+" role:: "+role+ "financialYear:: "+ financialYear+" auditTypeCode:: "+auditTypeCode);
		if (!BankAuditUtil.isEmptyString(drawStr) && !BankAuditUtil.isEmptyString(length)
				&& !BankAuditUtil.isEmptyString(start)) {
			try {
				Integer draw = Integer.parseInt(drawStr);
				Integer size = Integer.parseInt(length);
				Integer page = Integer.parseInt(start) / size;
				Integer orderColumn = null;
				if (!BankAuditUtil.isEmptyString(orderColumnStr)) {
					orderColumn = Integer.parseInt(orderColumnStr);
				}
				dataTableResponse = lettersService.getLetterForReviewer(Integer.parseInt(legalEntityCodeStr),userId,search, orderColumn, orderDirection, page, size, role, userUnitType, financialYear, auditTypeCode);
				logger.info("Inside controller dataTableResponse .... "+dataTableResponse);
				dataTableResponse.setDraw(draw);

			} catch (Exception e) {
				dataTableResponse = new DataTableResponse();
				dataTableResponse.setError(e.getMessage());
				e.printStackTrace();
			}

		} else {
			dataTableResponse = new DataTableResponse();
			dataTableResponse.setError("invalid data");
		}

		return dataTableResponse;
	}
	
	
@RequestMapping(value="/isRatingCompleted",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus isRatingCompleted(
			@RequestParam("legalEntityCode") Integer legalEntityCode,
			@RequestParam("auditTypeCode")String auditTypeCode,
			@RequestParam("auditId") String auditId ){
		
		ServiceStatus serviceStatus=new ServiceStatus();	
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(auditTypeCode)  && !BankAuditUtil.isEmptyString(auditId)){
		 	 
			Integer count = lettersService.isRatingCompleted(legalEntityCode, auditTypeCode, auditId);
			if(count >0){
				serviceStatus.setStatus("success");
				serviceStatus.setMessage("success"); 
			}else if(count == 0 ){
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("Please review the Rating before authorizing the RN");
			}else{
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure"); 
			}
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
		return serviceStatus;	 
	}
	
	// To verify a particular letter is authorized or not
	
@RequestMapping(value="/isLetterAuthorised",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	ServiceStatus isLetterAuthorised(
			@RequestParam("legalEntityCode") Integer legalEntityCode,
			@RequestParam("auditTypeCode")String auditTypeCode,
			@RequestParam("auditId") String auditId,
			@RequestParam("letterCode") String letterCode ){
		
		ServiceStatus serviceStatus=new ServiceStatus();	
		if(legalEntityCode!=null && !BankAuditUtil.isEmptyString(auditTypeCode) && !BankAuditUtil.isEmptyString(auditId) && !BankAuditUtil.isEmptyString(letterCode)){
		 	 
			Integer count = lettersService.isLetterAuthorised(legalEntityCode, auditTypeCode, auditId, letterCode);
			if(count >0){
				serviceStatus.setStatus("success");
				serviceStatus.setMessage("success"); 
			}else if(count == 0 && "CmpRating".equals(letterCode)){
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("Please review the Composite Rating before authorizing the RN");
			}else if(count == 0 ){
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("Please review the "+ letterCode +"before authorizing the RN");
			}else{
				serviceStatus.setStatus("failure");
				serviceStatus.setMessage("failure"); 
			}
		}else {
			serviceStatus.setStatus("failure");
			serviceStatus.setMessage("invalid parameter");
		}
		return serviceStatus;	 
	}
	
	
@RequestMapping(value = "/getLetterForReviewerGradingCompliance", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	DataTableResponse getLetterForReviewerGradingCompliance(
			@RequestParam("draw") String drawStr,
			@RequestParam("length") String length,
			@RequestParam("start") String start,
			@RequestParam("search[value]") String search,
			@RequestParam("order[0][column]") String orderColumnStr,
			@RequestParam("order[0][dir]") String orderDirection,
			@RequestParam("legalEntityCode") Integer legalEntityCode,
			@RequestParam("userId")String userId,
			@RequestParam("role")String role,
			@RequestParam("userUnitType")String userUnitType,
			@RequestParam(required = false, value = "financialYear") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate financialYear,
			@RequestParam(required = false, value = "auditTypeCode") String auditTypeCode){

		DataTableResponse dataTableResponse = null;

		if (!BankAuditUtil.isEmptyString(drawStr) && !BankAuditUtil.isEmptyString(length)
				&& !BankAuditUtil.isEmptyString(start)) {
			try {
				Integer draw = Integer.parseInt(drawStr);
				Integer size = Integer.parseInt(length);
				Integer page = Integer.parseInt(start) / size;
				Integer orderColumn = null;
				if (!BankAuditUtil.isEmptyString(orderColumnStr)) {
					orderColumn = Integer.parseInt(orderColumnStr);
				}
				System.out.println("getLetterForReviewerGradingCompliance :: legalEntityCode:: "+legalEntityCode +" userId:: "+ userId);
				dataTableResponse = lettersService.getLetterForReviewerGradingCompliance(legalEntityCode, userId, search, orderColumn, orderDirection, page, size, role, userUnitType, financialYear, auditTypeCode);
				System.out.println("Inside controller dataTableResponse .... "+dataTableResponse);
				dataTableResponse.setDraw(draw);

			} catch (Exception e) {
				dataTableResponse = new DataTableResponse();
				dataTableResponse.setError(e.getMessage());
				e.printStackTrace();
			}

		} else {
			dataTableResponse = new DataTableResponse();
			dataTableResponse.setError("invalid data");
		}

		return dataTableResponse;
	}
	

}
