package com.bankaudit.rest.process.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.type.StandardBasicTypes;
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.dao.UserDao;
import com.bankaudit.dto.DataTableResponse;
import com.bankaudit.model.User;
import com.bankaudit.process.model.AdhocPlanFinalV;
import com.bankaudit.process.model.AuditPlan;
import com.bankaudit.process.model.AuditPlanV;
import com.bankaudit.process.model.AuditPlanWrk;
import com.bankaudit.process.model.AuditProcessV;
import com.bankaudit.process.model.AuditProcessValidate;
import com.bankaudit.process.model.AuditSchedule;
import com.bankaudit.process.model.AuditTeam;
import com.bankaudit.rest.process.dao.AuditProcessVDao;
import com.bankaudit.util.BankAuditUtil;

/**
 * 
 * @author narendar.burada
 *
 */
@Service("auditProcessVService")
@Transactional("transactionManager")
public class AuditProcessVServiceImpl implements AuditProcessVService {

	@Autowired(required = true)
	AuditProcessVDao auditProcessVDao;
	
	@Autowired(required = true)
	UserDao userDao;

	static final Logger logger = Logger.getLogger(AuditProcessVServiceImpl.class);
	
	@Override
	public List<AuditProcessV> getAuditProcessByAuditPlan(int legalEntityCode, String auditType, String planStartDate, String planEndDate,
			String maker) {

		// Date psDate = BankAuditUtil.parseDate(planStartDate);
		// Date peDate = BankAuditUtil.parseDate(planEndDate);

		Date psDate = BankAuditUtil.parseDateTime(planStartDate);
		Date peDate = BankAuditUtil.parseDateTime(planEndDate);

		String plnStDate = BankAuditUtil.parseDateToString(psDate);
		String plnEnDate = BankAuditUtil.parseDateToString(peDate);

		System.out.println("Pls SD :" + plnStDate);
		System.out.println("Pls SE :" + plnEnDate);

		List<AuditProcessV> apl = auditProcessVDao.getAuditProcessByAuditPlan(legalEntityCode, auditType, plnStDate, plnEnDate, maker);
		// List<AuditProcessV> modified =
		// auditProcessVDao.checkAndsetStartDateforAuditProcess(apl,
		// plnStDate,plnEnDate);
		// List<AuditProcessV> beforeSetCountList=
		// auditProcessVDao.getAuditProcessAsPerFrequnacy(plnStDate,plnEnDate,modified);
		/*
		 * List finalList=new ArrayList<>(); long count=1; AuditProcessV apv
		 * =null;
		 * 
		 * for (AuditProcessV auditProcessV : beforeSetCountList) {
		 * apv=auditProcessV; apv.setRowNum(count); count++;
		 * 
		 * finalList.add(apv); System.out.println(apv); apv=null; }
		 * 
		 * apl=null; modified=null; beforeSetCountList=null;
		 * 
		 * return finalList;
		 */

		// return beforeSetCountList;
		return apl;
	}

	public DataTableResponse getAuditSchedules(int legalEntityCode, String search, Integer orderColumn, String orderDirection, Integer page,
			Integer size, String maker, String planType) {
		DataTableResponse ds = auditProcessVDao.getAuditSchedules(legalEntityCode, search, orderColumn, orderDirection, page, size, maker, planType);
		return ds;

	}

	public List<AuditPlanV> getAuditProcessNextPlan(int legalEntityCode, String auditTypeCode) {
		List<AuditPlanV> ls = auditProcessVDao.getAuditProcessNextPlan(legalEntityCode, auditTypeCode);
		if (ls != null)
			System.out.println(ls);

		return ls;

	}
	
	public List<AuditPlanV> getAuditProcessNextPlan(int legalEntityCode, String auditTypeCode, String plannerUnitCode) {
		List<AuditPlanV> ls = auditProcessVDao.getAuditProcessNextPlan(legalEntityCode, auditTypeCode, plannerUnitCode);
		if (ls != null)
			logger.info(ls);

		return ls;

	}

	public String previousAuditDetails(int legalEntityCode, String auditType, String unitCode, String auditId) {
		return auditProcessVDao.previousAuditDetails(legalEntityCode, auditType, unitCode, auditId);
	}

	public List getauditProcessTeam(int legalEntityCode, String auditType, String userId) {
		return auditProcessVDao.getauditProcessTeam(legalEntityCode, auditType, userId);
	}
	
	public List getauditProcessPIOTeam(int legalEntityCode, String auditType, String userId) {
		return auditProcessVDao.getauditProcessPIOTeam(legalEntityCode, auditType, userId);
	}
	
	public Map<String, String> isValiedBusinessDate(String legalEntityCode, String unitId, String frequency, int duration, String currStartDate,
			String currEndDate, String plnStDate, String plnEnDate) {
		return auditProcessVDao.isValiedBusinessDate(legalEntityCode, unitId, frequency, duration, currStartDate, currEndDate, plnStDate, plnEnDate);
	}

	@Override
	public void createAuditPlanTemp(List<AuditProcessValidate> auditProcessValidate) {
		auditProcessVDao.createAuditPlanTemp(auditProcessValidate);
	}

	public String skillSetValidation(String legalEntityCode, String userId, String unitCode, String auditTypeCode) {
		return auditProcessVDao.skillSetValidation(legalEntityCode, userId, unitCode, auditTypeCode);
	}

	@Override
	public void deleteAuditPlanTemp(int legalEntityCode, String maker) {
		// TODO Auto-generated method stub
		auditProcessVDao.deleteAuditPlanTemp(legalEntityCode, maker);
	}

	@Override
	public Map<String, Object> validateAuditProcess(AuditProcessValidate apv) {
		// TODO Auto-generated method stub
		Map<String, Object> mp = new Hashtable<>();

		List<AuditProcessValidate> avpList = auditProcessVDao.validateAuditProcess(apv.getLegalEntityCode(), apv.getAuditTypeCode(),
				apv.getPlanStartDate(), apv.getPlanEndDate(), apv.getRemarkPlanIds(), apv.getMaker());
		Object[] obj = auditProcessVDao.isValiedPlan(apv.getLegalEntityCode(), apv.getAuditTypeCode(), apv.getMaker());

		if ((avpList != null && !avpList.isEmpty()) && obj != null) {

			mp.put("Records", avpList);
			mp.put("isValidData",
					((obj[0] != null && obj[0].toString().equals("N")) ? "Please select mandatory fields for at least one record." : "Yes"));
			mp.put("isErrorExist",
					((obj[1] != null && obj[1].toString().equals("Y")) ? "Please correct the plan, there are some errors exist." : "No"));

			mp.put("ErrorCountZero", obj[2]);
			mp.put("ErrorCountOne", obj[3]);
			mp.put("ErrorCountTwo", obj[4]);
			mp.put("ErrorCountThree", obj[5]);
			mp.put("ErrorCountFour", obj[6]);
			mp.put("ErrorCountFive", obj[7]);

			mp.put("noneValidtedRecords", obj[8]);
			mp.put("totalRecords", obj[9]);

			mp.put("errorCountZeroMessage", obj[10]);
			mp.put("errorCountOneMessage", obj[11]);
			mp.put("errorCountTwoMessage", obj[12]);
			mp.put("errorCountThreeMessage", obj[13]);
			mp.put("errorCountFourMessage", obj[14]);
			mp.put("errorCountFiveMessage", obj[15]);

			validateForNewWarnings(avpList, mp, apv.getLegalEntityCode());
		}

		return mp;
	}
	
	@Override
	public Map<String, Object> validateAuditUpdateProcess(AuditProcessValidate apv) {
		// TODO Auto-generated method stub
		Map<String, Object> mp = new Hashtable<>();
		logger.info("Inside validateAuditUpdateProcess .. "+apv.getLegalEntityCode()+" :: "+ apv.getAuditId()+" :: "+ apv.getUnitId() +" :: "+apv.getTeamLead());
		logger.info("Sch St date:: "+ apv.getStartDate()+" :: "+apv.getEndDate()+" Plan st date:: "+apv.getPlanStartDate() +" :: "+apv.getPlanEndDate());
		int legalEntityCode= apv.getLegalEntityCode();		
		try {
		List<String> aioList=new ArrayList<>();
		if(apv.getMember()!=null) { 
			String[] aios = apv.getMember().split(","); 
			for(String aio: aios) aioList.add(aio);
		}
		
		// Logic to verify the Start and End date
		boolean startGraterEndDate=false;
		if(apv.getStartDate().compareTo(apv.getEndDate()) > 0)  startGraterEndDate=true;
		
		// Logic to verify the Start and End date
		boolean dateInValid=false;
		
		if("AP".equalsIgnoreCase(apv.getAuditStatus())) {
			try {
			// Logic to validate the business date
			//Map<String, String> validateDate= auditProcessVDao.isValiedBusinessDate(legalEntityCode, apv.getUnitId(), frequency, duration, currStartDate, currEndDate, plnStDate, plnEnDate)
				//Map<String, String> validateDate= auditProcessVDao.isValiedBusinessDate(String.valueOf(legalEntityCode), apv.getUnitId(), apv.getFrequency(), apv.getDuration(), apv.getStartDate().toString(), apv.getEndDate().toString(), (apv.getPlanStartDate()!=null?apv.getPlanStartDate().toString():null), (apv.getPlanEndDate()!=null?apv.getPlanEndDate().toString():null));
				//if(validateDate!=null && "0".equalsIgnoreCase(validateDate.get("validDate"))) dateInValid=true;
			}catch(Exception e) {e.printStackTrace(System.out);}	
		}
		
		// Logic to write the check the Grade 
		
		// Logic to verify the AIO PIO part of other inspection during same time
		if(aioList !=null) aioList.add(apv.getTeamLead());
		boolean aioPioConflict=auditProcessVDao.isAuditorsConflict(legalEntityCode, apv.getAuditId(), apv.getStartDate(), apv.getEndDate(), aioList);
		
		// Logic to verify the Unit inspected during the same period
		boolean unitConflict=auditProcessVDao.isUnitInspectingSametime(legalEntityCode, apv.getAuditId(), apv.getUnitId(), apv.getAuditTypeCode(), apv.getStartDate(), apv.getEndDate());
				
		/************ Code for Warnings start here ******************/
		// Logic to verify the Effort mismatch
		boolean effortMismatch=false;
		if("AP".equalsIgnoreCase(apv.getAuditStatus())) {
			effortMismatch=auditProcessVDao.isEffortMismatch(legalEntityCode, apv.getAuditId(), apv.getStartDate(), apv.getEndDate(), aioList);
		}
		
		// Logic to verify the AIO grades higher than PIO
		boolean isAioGradeLow=true;
		try {
			Map<String, Integer> userGrades= userDao.getUserGrades(legalEntityCode, aioList);
			int leadGrade=userGrades.get(apv.getTeamLead());
			userGrades.remove(apv.getTeamLead());
			for (Map.Entry<String,Integer> grades : userGrades.entrySet()) { 
	            if(leadGrade < grades.getValue()) isAioGradeLow= false;
			}	
		}catch(Exception e) {e.printStackTrace(System.out);}
		
		// Logic to find IO may not be available due to the ongoing previous inspection
		boolean isAuditorsAvailableDuetoPrevAudit=auditProcessVDao.isAuditorsAvailableDuetoPrevAudit(legalEntityCode, apv.getAuditId(), apv.getAuditTypeCode(), apv.getUnitId(), aioList);
				
		// Logic to find IO belongs to previous inspection
		boolean isAuditorsBelongstoPrevAudit=auditProcessVDao.isAuditorsBelongstoPrevAudit(legalEntityCode, apv.getAuditId(), apv.getAuditTypeCode(), apv.getUnitId(), aioList);
				
		// Logic to find IO belongs to same office or not
		boolean isAuditorsBelongstoSameOffice=auditProcessVDao.isAuditorsBelongstoSameOffice(legalEntityCode,  apv.getUnitId(), aioList);
						
		//List<AuditProcessValidate> avpList = auditProcessVDao.validateAuditProcess(apv.getLegalEntityCode(), apv.getAuditTypeCode(),
		//		apv.getPlanStartDate(), apv.getPlanEndDate(), apv.getRemarkPlanIds(), apv.getMaker());
		//Object[] obj = auditProcessVDao.isValiedPlan(apv.getLegalEntityCode(), apv.getAuditTypeCode(), apv.getMaker());

		//if ((avpList != null && !avpList.isEmpty()) && obj != null) {

			//mp.put("Records", avpList);
			mp.put("Record", apv);
			mp.put("ErrorCountZero", startGraterEndDate==true?"1":"0"); //Start/End date incorrect
			mp.put("ErrorCountOne", dateInValid==true?"1":"0");
			mp.put("ErrorCountTwo", aioPioConflict==true?"1":"0");  // Users conflict
			mp.put("ErrorCountThree", unitConflict==true?"1":"0"); // Unit date same
			mp.put("ErrorCountFour", "0");
			mp.put("ErrorCountFive", "0");

			mp.put("noneValidtedRecords", "");
			mp.put("totalRecords", "");

			mp.put("errorCountZeroMessage", "Start/end date are incorrect.");
			mp.put("errorCountOneMessage", "InValid business Dates.");
			mp.put("errorCountTwoMessage", "Users are conflicting.");
			mp.put("errorCountThreeMessage", "Unit Shedules are conflicting.");
			mp.put("errorCountFourMessage", "Skill Set missmatch.");
			mp.put("errorCountFiveMessage", "Persons and duration required to audit is less/more sufficient");
			
			mp.put("warningCount1", isAioGradeLow==true?0:1);
			mp.put("warningCount2", isAuditorsAvailableDuetoPrevAudit==true?0:1);
			mp.put("warningCount3", isAuditorsBelongstoPrevAudit==true?1:0);
			mp.put("warningCount4", isAuditorsBelongstoSameOffice==true?0:1);
			mp.put("warningCount5", effortMismatch==true?1:0);
			
			//List<AuditProcessValidate> avpList=new ArrayList<>();
			//avpList.add(apv);
			//validateForNewWarnings(avpList, mp, apv.getLegalEntityCode());
			logger.info("map is .. "+ mp);
		}catch(Exception e) {
			e.printStackTrace(System.out);
		}
		return mp;
	}

	private Map<String, Object> validateForNewWarnings(List<AuditProcessValidate> avpList, Map<String, Object> mp, Integer legalEntityCode) {
		try {
			int warningCount1 = 0;
			int warningCount2 = 0;
			int warningCount3 = 0;
			int warningCount4 = 0;
			Map<String, String> userGrademap = auditProcessVDao.getUserGradeMap(legalEntityCode);
			for (AuditProcessValidate avp : avpList) {
				String userIds = avp.getTeamLead();
				if (avp.getMember() != null)
					userIds = userIds + "," + avp.getMember();
				if (userIds != null && !userIds.isEmpty()) {
					if (avp.getTeamLead() != null && avp.getMember() != null) {
						String grade = compareUserGrades(avp.getTeamLead(), avp.getMember(), userGrademap);
						if (grade!=null && !grade.isEmpty()) {
							warningCount1++;
							if (avp.getRemarkDesc() == null || avp.getRemarkDesc().isEmpty()) {
								avp.setRemarkDesc("The grade of member " + grade + " is higher than that of the Leader " + avp.getTeamLead());
							}
						}
					}
					try {
					String userPresentInLast = auditProcessVDao.validateAuditInspectionProcessPreviosDate(avp.getLegalEntityCode(), userIds,
							avp.getStartDate());
					if (!userPresentInLast.isEmpty()) {
						warningCount2++;
						if (avp.getRemarkDesc() == null || avp.getRemarkDesc().isEmpty()) {
							avp.setRemarkDesc(userPresentInLast + " may not be available due to previous inspection. Please verify");
						}
					}
					}catch(Exception e) {
						e.printStackTrace(System.out);
					}
					List<AuditTeam> lastList = auditProcessVDao.immediatePrecedinginSpection(avp.getLegalEntityCode(), avp.getAuditTypeCode(),
							avp.getRemarkPlanIds(), avp.getMaker(), avp.getUnitId(), avp.getTeamLead() + "," + avp.getMember());
					if (!lastList.isEmpty()) {
						warningCount3++;
						if (avp.getRemarkDesc() == null || avp.getRemarkDesc().isEmpty()) {
							avp.setRemarkDesc(lastList.get(0).getUserId() + " was part of the team for the last inspection");
						}
					}
					String sameRegion = auditProcessVDao.userIsFromOtherRegion(avp.getLegalEntityCode(), avp.getAuditTypeCode(), avp.getUnitId(),
							userIds);
					if (!sameRegion.isEmpty()) {
						warningCount4++;
						if (avp.getRemarkDesc() == null || avp.getRemarkDesc().isEmpty()) {
							avp.setRemarkDesc(sameRegion + " does not belong to your office. Do you want to select");
						}
					}
				}
			}
			mp.put("warningCount1", warningCount1);
			mp.put("warningCount2", warningCount2);
			mp.put("warningCount3", warningCount3);
			mp.put("warningCount4", warningCount4);
			return mp;
		} catch (Exception e) {
			e.printStackTrace(System.out);
		}
		return mp;
	}
	private String compareUserGrades(String teamLead, String member, Map<String, String> userGrademap) {
		if(!teamLead.isEmpty() && member != null && !member.isEmpty()) {
			String[] memberList = member.split(",");
			for(String m : memberList) {
				if(userGrademap.get(teamLead).compareTo(userGrademap.get(m)) < 0) {
					return m;
				}
			}
		}
		return null;
	}

	public List<AuditProcessValidate> getValidateAuditProcess(int legalEntityCode, String auditTypeCode) {
		return auditProcessVDao.getValidateAuditProcess(legalEntityCode, auditTypeCode);
	}

	@Override
	public AuditPlan getAuditByPlanId(int legalEntityCode, String auditTypeCode, String planId) {
		AuditPlan auditsList = auditProcessVDao.getAuditByPlanId(legalEntityCode, auditTypeCode, planId);
		return auditsList;
	}

	@Override
	public Map financialYearDates(int legalEntityCode) {
		return auditProcessVDao.financialYearDates(legalEntityCode);
	}

	public String getWatchListForAllAudits(int legalEntityCode, String auditTypeCode) {
		return auditProcessVDao.getWatchListForAllAudits(legalEntityCode, auditTypeCode);
	}

	public Map jurisdictionByShedule(int legalEntityCode, String units, String auditTypeCode, String plnStDate, String plnEnDate) {
		return auditProcessVDao.jurisdictionByShedule(legalEntityCode, units, auditTypeCode, plnStDate, plnEnDate);
	}

	@Override
	public boolean isAuditorsExist(int legalEntityCode) throws Exception {

		return auditProcessVDao.isAuditorsExist(legalEntityCode);
	}

	public boolean isAuditParametersExist(int legalEntityCode, String auditTypeCode) throws Exception {
		return auditProcessVDao.isAuditParametersExist(legalEntityCode, auditTypeCode);
	}

	public List getAllUnits(int legalEntityCode, String search) {
		return auditProcessVDao.getAllUnits(legalEntityCode, search);
	}

	public List<AdhocPlanFinalV> getAdhocPlan(int legalEntityCode, String auditTypeCode, String unitCode, String currBusinesDate) {
		return auditProcessVDao.getAdhocPlan(legalEntityCode, auditTypeCode, unitCode, currBusinesDate);
	}

	/*
	 * public List<AdhocPlanFinalV> getAdhocPlan(int legalEntityCode,String
	 * auditTypeCode,String planId){ return
	 * auditProcessVDao.getAdhocPlan(legalEntityCode,auditTypeCode,planId); }
	 */

	public String getAdhocUnitSheduleDetails(int legalEntityCode, String auditTypeCode, String unitCode, String currBusinesDate) {
		return auditProcessVDao.getAdhocUnitSheduleDetails(legalEntityCode, auditTypeCode, unitCode, currBusinesDate);
	}

	public Long getOperationAuditUnits(int legalEntityCode, String auditType, String unitIds) throws Exception {
		return auditProcessVDao.getOperationAuditUnits(legalEntityCode, auditType, unitIds);
	}

	public Long getAllOperationAuditUnits(int legalEntityCode, String auditType, String unitIds) throws Exception {
		return auditProcessVDao.getAllOperationAuditUnits(legalEntityCode, auditType, unitIds);
	}

	public Long numberOfBusinessDaysBtweenStartEndDates(String legalEntityCode, String unitCode, String StDate, String EnDate) {
		return auditProcessVDao.numberOfBusinessDaysBtweenStartEndDates(legalEntityCode, unitCode, StDate, EnDate);
	}

	@Override
	public Long getTargetAudits(int legalEntityCode, String units, String auditTypeCode, String userOrUnitCode) {

		return auditProcessVDao.getTargetAudits(legalEntityCode, units, auditTypeCode, userOrUnitCode);
	}
	@Override
	public List<AuditProcessV> getAssessmentsByAuditType(int legalEntityCode, String auditType, String planStartDate, String planEndDate,
			String maker) {

		// Date psDate = BankAuditUtil.parseDate(planStartDate);
		// Date peDate = BankAuditUtil.parseDate(planEndDate);

		Date psDate = BankAuditUtil.parseDateTime(planStartDate);
		Date peDate = BankAuditUtil.parseDateTime(planEndDate);

		String plnStDate = BankAuditUtil.parseDateToString(psDate);
		String plnEnDate = BankAuditUtil.parseDateToString(peDate);

		System.out.println("Pls SD :" + plnStDate);
		System.out.println("Pls SE :" + plnEnDate);

		List<AuditProcessV> apl = auditProcessVDao.getAssessmentsByAuditType(legalEntityCode, auditType, plnStDate, plnEnDate, maker);

		return apl;
	}

	public List getRiskAssessorsTeam(int legalEntityCode, String auditType, String unitCode, String userId) {
		return auditProcessVDao.getRiskAssessorsTeam(legalEntityCode, auditType, unitCode, userId);
	}
	public List getRiskAssessorsTeamChekcer(int legalEntityCode, String auditType, String unitCode, String userId) {
		return auditProcessVDao.getRiskAssessorsTeamChekcer(legalEntityCode, auditType, unitCode, userId);
	}
	
	public List<AuditPlanWrk> isPlanAlreadyExist(int legalEntityCode,String userId,String parentUnitCode,String auditTypeCode) {
		return auditProcessVDao.isPlanAlreadyExist(legalEntityCode, userId, parentUnitCode, auditTypeCode);
	}
	
	@Override
	public List<AuditProcessV> getAuditProcessByAuditPlanAtParent(int legalEntityCode,String auditType,String parentUnitCode, 
			String planStartDate, String planEndDate,String maker) {

		Date psDate = BankAuditUtil.parseDateTime(planStartDate);
		Date peDate = BankAuditUtil.parseDateTime(planEndDate);

		String plnStDate = BankAuditUtil.parseDateToString(psDate);
		String plnEnDate = BankAuditUtil.parseDateToString(peDate);

		System.out.println("Pls SD :" + plnStDate);
		System.out.println("Pls SE :" + plnEnDate);

		List<AuditProcessV> apl = auditProcessVDao.getAuditProcessByAuditPlanAtParent(legalEntityCode, auditType, parentUnitCode, plnStDate, plnEnDate, maker);
				return apl;
	}
	
	
	public Map<String, String> isDateFallOnFortnight(String legalEntityCode,String unitId,String currDate) {
		return auditProcessVDao.isDateFallOnFortnight(legalEntityCode, unitId, currDate);
	}
	
	public Map<String, String> isDateFallOnHoliday(String legalEntityCode,String unitId,String currDate) {
		return auditProcessVDao.isDateFallOnHoliday(legalEntityCode, unitId, currDate);
		
	}

	
}
