package com.nisum.myteam.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.mongodb.WriteResult;
import com.nisum.myteam.exception.handler.MyTeamException;
import com.nisum.myteam.model.Account;
import com.nisum.myteam.model.Domain;
import com.nisum.myteam.model.Employee;
import com.nisum.myteam.model.EmployeeRole;
import com.nisum.myteam.model.Resource;
import com.nisum.myteam.repository.EmployeeRepo;
import com.nisum.myteam.service.IAccountService;
import com.nisum.myteam.service.IDomainService;
import com.nisum.myteam.service.IEmployeeLocationService;
import com.nisum.myteam.service.IEmployeeRoleService;
import com.nisum.myteam.service.IEmployeeService;
import com.nisum.myteam.service.IProjectService;
import com.nisum.myteam.service.IResourceService;
import com.nisum.myteam.utils.MyTeamUtils;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class EmployeeService implements IEmployeeService {



	@Autowired
	private EmployeeRepo employeeRepo;
	
	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private IAccountService accountService;

	@Autowired
	private IProjectService projectService;

	@Autowired
	private IDomainService domainService;

	@Autowired
	private IEmployeeRoleService employeeRoleService;

	@Autowired
	private IEmployeeLocationService empLocationService;

	@Autowired
	private IResourceService resourceService;

	@Override
	public Employee createEmployee(Employee employee, String loginEmpId) throws MyTeamException {
		employee.setCreatedOn(new Date());
		employee.setCreatedBy(loginEmpId);
		employee.setModifiedBy(loginEmpId);

		// adding employee to Bench Allocation
		projectService.addNewBeanchAllocation(employee, loginEmpId);

		// Saving employee Location Details.
		empLocationService.save(employee);

		return employeeRepo.save(employee);
	}

	@Override
	public Employee updateEmployee(Employee employeeReq, String loginEmpId) {
		// update all emp details to inactive if employee is inactive
		Query query = new Query(Criteria.where("employeeId").is(employeeReq.getEmployeeId()));
		Update update = new Update();
		update.set("employeeName", employeeReq.getEmployeeName());
		update.set("emailId", employeeReq.getEmailId());
		update.set("role", employeeReq.getRole());
		update.set("gender", employeeReq.getGender());
		update.set("functionalGroup", employeeReq.getFunctionalGroup());
		update.set("empStatus", employeeReq.getEmpStatus());
		update.set("employmentType", employeeReq.getEmploymentType());
		update.set("empLocation", employeeReq.getEmpLocation());
		update.set("domain", employeeReq.getDomain());
		update.set("designation", employeeReq.getDesignation());
		update.set("dateOfBirth", employeeReq.getDateOfBirth());
		update.set("dateOfJoining", employeeReq.getDateOfJoining());
		update.set("lastModifiedOn", new Date());
		update.set("hasPassort", employeeReq.getHasPassort());
		update.set("hasB1", employeeReq.getHasB1());
		update.set("passportExpiryDate", employeeReq.getPassportExpiryDate());
		update.set("b1ExpiryDate", employeeReq.getB1ExpiryDate());

		update.set("modifiedBy", loginEmpId);

		if (employeeReq.getEmpStatus().equalsIgnoreCase(MyTeamUtils.IN_ACTIVE_SPACE)) {
			update.set("endDate", employeeReq.getEndDate());
		}
		// update employee location
		if (employeeReq.getEmpLocation() != null && !employeeReq.getEmpLocation().equals("")) {
			Employee existingEmployee = employeeRepo.findByEmployeeId(employeeReq.getEmployeeId());
			if (!existingEmployee.getEmpLocation().equals(employeeReq.getEmpLocation())) {
				empLocationService.update(employeeReq, false);
			}

		}

		// update employee details
		FindAndModifyOptions options = new FindAndModifyOptions();
		options.returnNew(true);
		options.upsert(true);
		Employee employeeUpdated = mongoTemplate.findAndModify(query, update, options, Employee.class);

		try {
			// add to resource collection
			resourceService.addResources(employeeUpdated, loginEmpId);

			// inactive the employee from the assigned project.
			resourceService.inactivateResource(employeeReq, employeeUpdated, loginEmpId);

		} catch (Exception e) {
		}
		return employeeUpdated;
	}

	@Override
	public Employee deleteEmployee(String employeeId) {
		// Employee employee = employeeRepo.findByEmployeeId(employeeId);
		// employee.setEmpStatus("InActive");
		// employeeRepo.save(employee);

		Query query = new Query();
		query.addCriteria(Criteria.where("employeeId").is(employeeId));
		Update update = new Update();
		update.set("empStatus", "InActive");
		Employee employeeUpdated = mongoTemplate.findAndModify(query, update, Employee.class);
		log.info("The Deletion operation Result::" + employeeUpdated);
		return employeeUpdated;
	}

	@Override
	public Employee updateProfile(Employee employeeReq) throws MyTeamException {
		boolean mobileNumberChanged = false;
		employeeReq.setLastModifiedOn(new Date());
		Employee existingEmployee = employeeRepo.findByEmployeeId(employeeReq.getEmployeeId());
		String newMobileNumber = employeeReq.getMobileNumber();
		if (newMobileNumber != null && !newMobileNumber.equalsIgnoreCase("")) {
			if ((existingEmployee != null && existingEmployee.getMobileNumber() != null
					&& !existingEmployee.getMobileNumber().equalsIgnoreCase(newMobileNumber))
					|| (existingEmployee.getMobileNumber() == null)) {
				mobileNumberChanged = true;
			}
		}
		existingEmployee.setMobileNumber(employeeReq.getMobileNumber());
		existingEmployee.setAlternateMobileNumber(employeeReq.getAlternateMobileNumber());
		existingEmployee.setPersonalEmailId(employeeReq.getPersonalEmailId());
		existingEmployee.setBaseTechnology(employeeReq.getBaseTechnology());
		existingEmployee.setTechnologyKnown(employeeReq.getTechnologyKnown());
		Employee employeePersisted = employeeRepo.save(existingEmployee);
		if (mobileNumberChanged) {
			try {
				List<Resource> resourcesList = resourceService.getResourcesForEmployee(employeeReq.getEmployeeId());

				if (resourcesList != null && !resourcesList.isEmpty()) {
					for (Resource resource : resourcesList) {
						resource.setMobileNumber(employeePersisted.getMobileNumber());
						resourceService.save(resource);
					}
					
				}
				
				
				
			} catch (Exception e) {
			}
		}
		return employeePersisted;

	}

	public boolean isEmployeeExistsById(String employeeId) {
		Employee employeeFound = getEmployeeById(employeeId);
		return (employeeFound == null) ? false : true;

	}

	@Override
	public Employee getEmployeeById(String employeeId) {
		log.info("The employeeId::"+employeeId);

		Employee employee=employeeRepo.findByEmployeeId(employeeId);
		log.info("Employee Found in Repo::"+employee);
		return employee;
	}

	@Override
	public Employee getEmployeeByEmaillId(String emailId) {
		return employeeRepo.findByEmailId(emailId);
	}

	public List<Employee> getManagers() throws MyTeamException {
		List<Employee> activeEmpsList = getActiveEmployees();
		List<Employee> managers = activeEmpsList.stream()
				.filter(e -> ("Director".equalsIgnoreCase(e.getRole())
						|| "Delivery Manager".equalsIgnoreCase(e.getRole()) || "Manager".equalsIgnoreCase(e.getRole())
						|| "HR Manager".equalsIgnoreCase(e.getRole()) || "Lead".equalsIgnoreCase(e.getRole())))
				.sorted(Comparator.comparing(Employee::getEmployeeName)).collect(Collectors.toList());
		return managers;
	}

	@Override
	public List<Employee> getActiveEmployees() throws MyTeamException {
		return employeeRepo.findByEmpStatus(MyTeamUtils.ACTIVE);
	}

	@Override
	public List<Employee> getEmployeesByStatus(String status) {
		if (status.equals("both")) {
			return employeeRepo.findAll(new Sort(Sort.Direction.ASC, "employeeName"));
		} else {
			return employeeRepo.findByEmpStatusOrderByEmployeeNameAsc(status);
		}
	}

	@Override
	public List<Account> getAccounts() throws MyTeamException {
		return accountService.getAccounts();

	}

	@Override
	public Employee getEmployeeRoleDataForSearchCriteria(String searchId, String searchAttribute) {
		if (MyTeamUtils.EMPLOYEE_NAME.equals(searchAttribute)) {
			return employeeRepo.findByEmployeeName(searchId);
		} else if (MyTeamUtils.EMAIL_ID.equals(searchAttribute)) {
			return employeeRepo.findByEmailId(searchId);
		}
		return null;

	}

	@Override
	public List<String> getEmployeeDetailsForAutocomplete() {
		List<Employee> employeeList = employeeRepo.findAll();
		List<String> resultList = new ArrayList<>();
		employeeList.stream().sorted(java.util.Comparator.comparing(Employee::getEmployeeId))
				.collect(Collectors.toList()).forEach(employee -> {
					resultList.add(employee.getEmployeeId());
				});
		employeeList.stream().sorted(java.util.Comparator.comparing(Employee::getEmployeeName))
				.collect(Collectors.toList()).forEach(employee -> {
					resultList.add(employee.getEmployeeName());
				});
		employeeList.stream().sorted(java.util.Comparator.comparing(Employee::getEmailId)).collect(Collectors.toList())
				.forEach(employee -> {
					resultList.add(employee.getEmailId());
				});
		return resultList;
	}

	@Override
	public List<HashMap<String, String>> getDeliveryLeads(String domainId) {
		Domain domain = domainService.getDomainById(domainId);
		return getDeliveryManagerMap(domain.getDeliveryManagers());
	}


	@Override
	 public List<HashMap<String, String>> getDeliveryManagerMap(List deliveryManagerIdsList) {
	        List<HashMap<String, String>> employeeList = new ArrayList<>();

	        Query query = new Query(Criteria.where("employeeId").in(deliveryManagerIdsList));
	        List<Employee> employeePersistedList = mongoTemplate.find(query,Employee.class);
	        for (Employee employee : employeePersistedList) {
	            HashMap<String, String> managerMap = new HashMap<>();
	            managerMap.put("employeeId", employee.getEmployeeId());
	            managerMap.put("employeeName", employee.getEmployeeName());
	            employeeList.add(managerMap);
	        }
	        return employeeList;
	    }
	 
	 
	@Override
	public List<Employee> getEmployeesByFunctionalGrp(String functionalGrp) {
		return employeeRepo.findByEmpStatusAndFunctionalGroup("Active", functionalGrp);

	}

	@Override
	public boolean verifyEmployeeRole(String empId, String roleName) {
		boolean flag = false;

		log.info("The employeeId::"+empId);

		Employee employee=getEmployeeById(empId);
		log.info("Employee::::in EmployeeService::"+employee);

		String role = employee.getRole();
		log.info("The employee role::"+role);
		if (null != role && "" != role && !"Admin".equalsIgnoreCase(role)) {
			Set<String> roleSet = employeeRoleService.empRolesMapInfoByEmpId(empId);
			if (null != roleSet && !roleSet.isEmpty() && MyTeamUtils.INT_ZERO < roleSet.size()) {
				if (roleSet.contains(roleName)) {
					flag = true;
				}
			}

		}
		return flag;
	}

	public List<Employee> getEmployeesFromList(Set<String> empIdsSet) {
		return employeeRepo.findByEmployeeIdIn(empIdsSet);

	}

	@Override
	public List<Employee> getAllEmployees() {
		return employeeRepo.findAll();
	}
	 
	
	
}
