package com.bankaudit.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bankaudit.constants.BankAuditConstant;
import com.bankaudit.dao.MaintRatingModelDao;
import com.bankaudit.dto.DataTableResponse;
import com.bankaudit.dto.process.MaintRatingModelDto;
import com.bankaudit.model.MaintFormula;
import com.bankaudit.model.MaintRatingCategory;
import com.bankaudit.model.MaintRatingGrade;
import com.bankaudit.model.MaintRatingModelOverlayWrk;
import com.bankaudit.model.MaintRatingModelWrk;
import com.bankaudit.model.MaintRatingParameterInputsWrk;
import com.bankaudit.model.MaintRatingParameterMappingWrk;
import com.bankaudit.model.MaintRatingParameterRangeWrk;
import com.bankaudit.model.MaintRatingParameterDtlsWrk;
import com.bankaudit.model.MaintRatingSubCategory;
import com.bankaudit.process.model.IfcRatingParameterMapping;
import com.bankaudit.util.BankAuditUtil; 
 
@Service("maintRatingModelService")
@Transactional("transactionManager")
public class MaintRatingModelServiceImpl implements MaintRatingModelService {

	static final Logger logger = Logger.getLogger(MaintRatingModelServiceImpl.class);
	
	@Autowired
	MaintRatingModelDao  maintRatingModelDao;
	
	@Autowired
	BusinessDateService businessDateService;
	
	public List<MaintRatingModelWrk> getRatingModelBy(Integer legalEntityCode, String rmCode, String status){
		return  maintRatingModelDao.getRatingModelBy(legalEntityCode, rmCode, status);		 
	}
	
	@Override
	public DataTableResponse getAllRatingModel(Integer legalEntityCode, String search,Integer orderColumn, String orderDirection, Integer page, Integer size){
		return maintRatingModelDao.getAllRatingModel(legalEntityCode, search, orderColumn, orderDirection, page, size);
	}
	
	@Override
	public  MaintRatingModelDto  getRatingModelParameterDetails(Integer legalEntityCode, String rmCode, String status){	 
		
		MaintRatingModelDto maintRatingModelDto =  new MaintRatingModelDto();
		
		//get Rating Model details
		List<MaintRatingModelWrk> ratingModelList = getRatingModelBy(legalEntityCode, rmCode, status);
		if(ratingModelList!=null && ratingModelList.size()>0){
			maintRatingModelDto.setMaintRatingModelWrk(ratingModelList.get(0));
			
			List<MaintRatingParameterDtlsWrk> parametersDetailsWrkList = maintRatingModelDao.getRatingParameterDetailsBy(legalEntityCode, rmCode, status);
			List<String> paramCode = parametersDetailsWrkList.stream().map(MaintRatingParameterDtlsWrk::getParamCode) .collect(Collectors.toList());
			maintRatingModelDto.setMaintRatingPrameterDtlsWrkList(parametersDetailsWrkList);	
			
			maintRatingModelDto.setMaintRatingParameterRangeWrkList(maintRatingModelDao.getRatingParameterRangeBy(legalEntityCode, rmCode, paramCode, status));
			maintRatingModelDto.setMaintRatingParameterCategoryMappingWrkList(maintRatingModelDao.getRatingParameterCategoryMappingBy(legalEntityCode, rmCode, paramCode, status));
			
			maintRatingModelDto.setMaintRatingModelOverlayWrkList(maintRatingModelDao.getRatingModelOverlayBy(legalEntityCode, rmCode, status)); 
		}
		
		return maintRatingModelDto;
		
	}
			
	@Override
	public MaintRatingModelWrk saveRatingModelParameterDetails(MaintRatingModelDto maintRatingModelDto) throws Exception{
		
		MaintRatingModelWrk maintRatingModelWrk= null;
		if(maintRatingModelDto!=null){ 
			//try{
				maintRatingModelWrk =  maintRatingModelDto.getMaintRatingModelWrk();
				List<MaintRatingParameterDtlsWrk>  maintRatingPrameterDtlsWrkList = maintRatingModelDto.getMaintRatingPrameterDtlsWrkList(); 
				List<MaintRatingParameterRangeWrk> maintRatingParameterRangeWrkList = maintRatingModelDto.getMaintRatingParameterRangeWrkList();
				List<MaintRatingParameterMappingWrk> maintRatingParameterCategoryMappingWrkList = maintRatingModelDto.getMaintRatingParameterCategoryMappingWrkList();
				List<MaintRatingModelOverlayWrk> maintRatingModelOverlayWrkList = maintRatingModelDto.getMaintRatingModelOverlayWrkList();		
				
				//if(!maintRatingModelWrk.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_AUTH)){
				Long dateValue = Long.parseLong(BankAuditUtil.parseDateToStringHHmmssddMMyyyy(new Date()));
				int appender = 1;
					if(maintRatingModelWrk!=null && maintRatingPrameterDtlsWrkList != null &&  maintRatingPrameterDtlsWrkList.size()>0){					 				
						 
						Integer legalEntityCode = maintRatingModelWrk.getLegalEntityCode();
						//String rmCode = "RM"+String.format("%03d", (maintRatingModelDao.countRatingModel(legalEntityCode)+1));					
						String rmCode = "RM0"+BankAuditUtil.parseDateToStringHHmmssddMMyyyy(new Date());
						
						maintRatingModelWrk.setRmCode(rmCode);
						maintRatingModelWrk.setBusinessdateTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(legalEntityCode));
						maintRatingModelDao.save(maintRatingModelWrk);						
						for (MaintRatingParameterDtlsWrk maintRatingPrameterDtlsWrk : maintRatingPrameterDtlsWrkList) {	
							/*long paramCodeCount = (maintRatingModelDao.countRatingModelParameter(legalEntityCode))+1;
							String paramCode = "P"+String.format("%04d", paramCodeCount);	*/
							
							String paramCode = "P00"+dateValue+"-"+(appender++);
							
							maintRatingPrameterDtlsWrk.setRmCode(rmCode);
							maintRatingPrameterDtlsWrk.setParamCode(paramCode);
							maintRatingModelDao.save(maintRatingPrameterDtlsWrk);							
							maintRatingModelDao.flushSession();
							
							if(!BankAuditUtil.isEmptyString(maintRatingPrameterDtlsWrk.getParamBasis()) 
									&& maintRatingPrameterDtlsWrk.getParamBasis().equalsIgnoreCase(BankAuditConstant.RATING_MODEL_PARAM_BASIC_CALCULATION)){
	 
								MaintRatingParameterInputsWrk maintRatingParameterInputsWrk= new MaintRatingParameterInputsWrk();
								maintRatingParameterInputsWrk.setLegalEntityCode(legalEntityCode);
								maintRatingParameterInputsWrk.setRmCode(rmCode);
								maintRatingParameterInputsWrk.setParamCode(paramCode);
								maintRatingParameterInputsWrk.setEntityStatus(maintRatingPrameterDtlsWrk.getEntityStatus());
								maintRatingParameterInputsWrk.setStatus(maintRatingPrameterDtlsWrk.getStatus());
								maintRatingParameterInputsWrk.setFormula(maintRatingPrameterDtlsWrk.getFactor());
								List<String> parameterInputsWrkList = maintRatingPrameterDtlsWrk.getMaintRatingParameterInputsWrkList();						
								for (int len=1; len<=parameterInputsWrkList.size(); len++) { 
									String input = "input"+String.format("%02d", len );	 				
									Field inputFiled = maintRatingParameterInputsWrk.getClass().getDeclaredField(input);
									inputFiled.setAccessible(true); 
									inputFiled.set(maintRatingParameterInputsWrk, parameterInputsWrkList.get(len-1) );							
								}
								maintRatingModelDao.save(maintRatingParameterInputsWrk);
							}
						}					
					}
					if(maintRatingParameterRangeWrkList !=null && maintRatingParameterRangeWrkList.size()>0 ){	
						appender = 1;
						for (MaintRatingParameterRangeWrk maintRatingParameterRangeWrk : maintRatingParameterRangeWrkList) {
							String rangeId = "RNG0"+dateValue+"-"+(appender++);
							maintRatingParameterRangeWrk.setId(rangeId);
							maintRatingModelDao.save(maintRatingParameterRangeWrk);
						}
					}
					if(maintRatingParameterCategoryMappingWrkList != null && maintRatingParameterCategoryMappingWrkList.size()>0) {						 
						for (MaintRatingParameterMappingWrk maintRatingParameterCategoryMappingWrk : maintRatingParameterCategoryMappingWrkList) {
							maintRatingModelDao.save(maintRatingParameterCategoryMappingWrk);
						}						
					}											
					if(maintRatingModelOverlayWrkList !=null && maintRatingModelOverlayWrkList.size()>0){
						appender = 1;
						for (MaintRatingModelOverlayWrk maintRatingModelOverlayWrk : maintRatingModelOverlayWrkList) {
							String criteriaCode = "CR0"+dateValue+"-"+(appender++);
							maintRatingModelOverlayWrk.setCriteriaCode(criteriaCode);
							maintRatingModelOverlayWrk.setBusinessdateTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(maintRatingModelOverlayWrk.getLegalEntityCode()));
							maintRatingModelDao.save(maintRatingModelOverlayWrk);
						}
					} 
				/*}else{
					return BankAuditConstant.FAILED;
				}*/
			/*}catch (Exception e) {
				logger.error(e);
				return BankAuditConstant.FAILED;
			}*/
		}
		return maintRatingModelWrk;
	}
	
	@Override
	public MaintRatingModelWrk updateRatingModelParameterDetails(MaintRatingModelDto maintRatingModelDto) throws Exception{
		
		MaintRatingModelWrk maintRatingModelWrk =null;	
		if(maintRatingModelDto!=null){
			//try{
				
				maintRatingModelWrk =  maintRatingModelDto.getMaintRatingModelWrk();
				List<MaintRatingParameterDtlsWrk>  maintRatingPrameterDtlsWrkList = maintRatingModelDto.getMaintRatingPrameterDtlsWrkList(); 
				List<MaintRatingParameterRangeWrk> maintRatingParameterRangeWrkList = maintRatingModelDto.getMaintRatingParameterRangeWrkList();
				List<MaintRatingParameterMappingWrk> maintRatingParameterCategoryMappingWrkList = maintRatingModelDto.getMaintRatingParameterCategoryMappingWrkList();
				List<MaintRatingModelOverlayWrk> maintRatingModelOverlayWrkList = maintRatingModelDto.getMaintRatingModelOverlayWrkList();		
				
				//if(!maintRatingModelWrk.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_AUTH)){
					Long dateValue = Long.parseLong(BankAuditUtil.parseDateToStringHHmmssddMMyyyy(new Date()));
					int appender = 1;
					if(maintRatingModelWrk!=null && maintRatingPrameterDtlsWrkList != null && maintRatingPrameterDtlsWrkList.size()>0){
						 										 
						Integer legalEntityCode = maintRatingModelWrk.getLegalEntityCode();
						String rmCode = maintRatingModelWrk.getRmCode(); 						
						
						maintRatingModelDao.saveOrUpdate(maintRatingModelWrk);
						for (MaintRatingParameterDtlsWrk maintRatingPrameterDtlsWrk : maintRatingPrameterDtlsWrkList) {							
							if(BankAuditUtil.isEmptyString(maintRatingPrameterDtlsWrk.getParamCode())){
								/*long paramCodeCount = (maintRatingModelDao.countRatingModelParameter(legalEntityCode))+1;
								String paramCode = "P"+String.format("%04d", paramCodeCount);	*/
								//String paramCode = "P00"+BankAuditUtil.parseDateToStringHHmmssddMMyyyy(new Date());
								String paramCode = "P00"+dateValue+"-"+(appender++);
								maintRatingPrameterDtlsWrk.setRmCode(rmCode);
								maintRatingPrameterDtlsWrk.setParamCode(paramCode);
								maintRatingModelDao.save(maintRatingPrameterDtlsWrk);							
								maintRatingModelDao.flushSession();								
								
							}else{
								maintRatingModelDao.saveOrUpdate(maintRatingPrameterDtlsWrk);							
								List<String> paramCode = new ArrayList<String>(); 
								paramCode.add(maintRatingPrameterDtlsWrk.getParamCode());							
								///delete and store parameter inputs
								maintRatingModelDao.deleteRatingParameterInputsFromWrkBy(legalEntityCode, rmCode, maintRatingPrameterDtlsWrk.getParamCode());
							}	
							if(!BankAuditUtil.isEmptyString(maintRatingPrameterDtlsWrk.getParamBasis()) 
									&& maintRatingPrameterDtlsWrk.getParamBasis().equalsIgnoreCase(BankAuditConstant.RATING_MODEL_PARAM_BASIC_CALCULATION)){
	 
								MaintRatingParameterInputsWrk maintRatingParameterInputsWrk= new MaintRatingParameterInputsWrk();
								maintRatingParameterInputsWrk.setLegalEntityCode(legalEntityCode);
								maintRatingParameterInputsWrk.setRmCode(rmCode);
								maintRatingParameterInputsWrk.setParamCode(maintRatingPrameterDtlsWrk.getParamCode());
								maintRatingParameterInputsWrk.setEntityStatus(maintRatingPrameterDtlsWrk.getEntityStatus());
								maintRatingParameterInputsWrk.setStatus(maintRatingPrameterDtlsWrk.getStatus());
								maintRatingParameterInputsWrk.setFormula(maintRatingPrameterDtlsWrk.getFactor());
								List<String> parameterInputsWrkList = maintRatingPrameterDtlsWrk.getMaintRatingParameterInputsWrkList();						
								for (int len=1; len<=parameterInputsWrkList.size(); len++) { 
									String input = "input"+String.format("%02d", len );	 				
									Field inputFiled = maintRatingParameterInputsWrk.getClass().getDeclaredField(input);
									inputFiled.setAccessible(true); 
									inputFiled.set(maintRatingParameterInputsWrk, parameterInputsWrkList.get(len-1) );							
								}
								maintRatingModelDao.save(maintRatingParameterInputsWrk);
							}							
						}					
					}
					if(maintRatingParameterRangeWrkList !=null && maintRatingParameterRangeWrkList.size()>0 ){
						//Delete from maintRatingParameterRange (existing score/range details)
						//maintRatingModelDao.deleteRatingParameterRangeBy(legalEntityCode, rmCode, paramCode, BankAuditConstant.STATUS_UNAUTH);
						
						//Save maintRatingParameterRange (existing score/range details)
						appender = 0;
						for (MaintRatingParameterRangeWrk maintRatingParameterRangeWrk : maintRatingParameterRangeWrkList) {
							//maintRatingParameterRangeWrk.setId(null);
							if(BankAuditUtil.isEmptyString(maintRatingParameterRangeWrk.getId())){
								String rangeId = "RNG0"+dateValue+"-"+(appender++);
								maintRatingParameterRangeWrk.setId(rangeId);
							}
							maintRatingModelDao.saveOrUpdate(maintRatingParameterRangeWrk);
						}
					} 
					
					if(maintRatingParameterCategoryMappingWrkList != null && maintRatingParameterCategoryMappingWrkList.size()>0) {						 
						for (MaintRatingParameterMappingWrk maintRatingParameterCategoryMappingWrk : maintRatingParameterCategoryMappingWrkList) {
							maintRatingModelDao.saveOrUpdate(maintRatingParameterCategoryMappingWrk);
						}						
					}	
					
					if(maintRatingModelOverlayWrkList !=null && maintRatingModelOverlayWrkList.size()>0){
						appender = 0;
						for (MaintRatingModelOverlayWrk maintRatingModelOverlayWrk : maintRatingModelOverlayWrkList) {							
							if(BankAuditUtil.isEmptyString(maintRatingModelOverlayWrk.getCriteriaCode())){
								String criteriaCode = "CR0"+dateValue+"-"+(appender++);
								maintRatingModelOverlayWrk.setCriteriaCode(criteriaCode);
							}
							maintRatingModelOverlayWrk.setBusinessdateTimestamp(businessDateService.getBusinessDateTimestampByLegalEntityCode(maintRatingModelOverlayWrk.getLegalEntityCode()));
							maintRatingModelDao.saveOrUpdate(maintRatingModelOverlayWrk);
						}
					} 
					 
				/*}else{
					return BankAuditConstant.FAILED;
				}*/
			/*}catch (Exception e) {
				logger.error(e);
				return BankAuditConstant.FAILED;
			}*/
		}
		return  maintRatingModelWrk;
	}
	
	@Override
	public String authorizeRatingModelParameterDetails(MaintRatingModelWrk maintRatingModelWrk) throws Exception{
		 
			//try{
			if(maintRatingModelWrk.getStatus().equalsIgnoreCase(BankAuditConstant.STATUS_AUTH)){
				Integer legalEntityCode = maintRatingModelWrk.getLegalEntityCode();
				String rmCode = maintRatingModelWrk.getRmCode(); 
				
				List<MaintRatingParameterDtlsWrk> parametersDetailsWrkList = 
						maintRatingModelDao.getRatingParameterDetailsBy(legalEntityCode, rmCode, BankAuditConstant.STATUS_UNAUTH);
				List<String> parametersCode = parametersDetailsWrkList.stream().map(MaintRatingParameterDtlsWrk::getParamCode) .collect(Collectors.toList());
				
				//delete parameter, score, category from master
				String statusAuth = BankAuditConstant.STATUS_AUTH;
				maintRatingModelDao.deleteRatingModelDetailsWhileAuthBy(legalEntityCode, rmCode, parametersCode, statusAuth); 
				
				
				//Store parameter, inputs, score, category into master from work 
				maintRatingModelDao.authorizeRatingModelParameterDetails(maintRatingModelWrk);
				
				//delete parameter, score, category from Work
				String statusUnAuth = BankAuditConstant.STATUS_UNAUTH;
				maintRatingModelDao.deleteRatingModelDetailsWhileAuthBy(legalEntityCode, rmCode, parametersCode, statusUnAuth); 
				
			/*}catch (Exception e) {
				logger.error(e);
				return BankAuditConstant.FAILED;
			}*/
			}else{
				maintRatingModelDao.saveOrUpdate(maintRatingModelWrk);
			}
		return BankAuditConstant.SUCCESS;
	}
	
	@Override
	public List<IfcRatingParameterMapping> getInputValues(Integer legalEntityCode, String auditTypeCode){
		return maintRatingModelDao.getInputValues(legalEntityCode, auditTypeCode);
	}

	@Override
	public List<MaintFormula> getFactor(Integer legalEntityCode, Integer noOfInputs){
		return maintRatingModelDao.getFactor(legalEntityCode, noOfInputs);
	}
	
	@Override
	public List<MaintRatingGrade> getGrades(Integer legalEntityCode, String rmCode){
		return maintRatingModelDao.getGrades(legalEntityCode, rmCode);
	}
	
	@Override
	public List<MaintRatingCategory> getRatingCategory(Integer legalEntityCode ){
		return maintRatingModelDao.getRatingCategory(legalEntityCode);
	}
	
	@Override
	public List<MaintRatingSubCategory> getRatingSubCategory(Integer legalEntityCode, String categoryCode){
		return maintRatingModelDao.getRatingSubCategory(legalEntityCode, categoryCode);
	}
		 
	@Override
	public void deleteRatingModelBy(Integer legalEntityCode, String rmCode, String status){
		maintRatingModelDao.deleteRatingModelBy(legalEntityCode, rmCode, status);
	}
	
	@Override
	public void deleteRatingParameterDetailsBy(Integer legalEntityCode, String rmCode, String paramCode, String status){
		maintRatingModelDao.deleteRatingParameterInputsBy(legalEntityCode, rmCode, paramCode, status);
		maintRatingModelDao.deleteRatingParameterRangeBy(legalEntityCode, rmCode, paramCode, null, status);
		maintRatingModelDao.deleteRatingParameterCategoryMappingBy(legalEntityCode, rmCode, paramCode,null, null, status);
		maintRatingModelDao.deleteRatingParameterDetailsBy(legalEntityCode, rmCode, paramCode, status);
	}	 
	
	@Override
	public void deleteRatingParameterRangeBy(Integer legalEntityCode, String rmCode, String paramCode, String id, String status){
		maintRatingModelDao.deleteRatingParameterRangeBy(legalEntityCode, rmCode, paramCode, id, status);
	}
	
	@Override
	public void deleteRatingParameterCategoryMappingBy(Integer legalEntityCode, String rmCode, String paramCode, String categoryCode, String subCategoryCode, String status){
		maintRatingModelDao.deleteRatingParameterCategoryMappingBy(legalEntityCode, rmCode, paramCode, categoryCode, subCategoryCode, status);
	}
	 
	@Override
	public void deleteRatingParameterModelOverlayBy(Integer legalEntityCode, String rmCode, String level,String categoryCode,  String criteriaCode, String status){
		maintRatingModelDao.deleteRatingParameterModelOverlayBy(legalEntityCode, rmCode, level, categoryCode, criteriaCode, status);
	}
}
