package com.nisum.mytime.service;

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

import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.util.StringUtils;

import com.mongodb.WriteResult;
import com.nisum.mytime.exception.handler.MyTimeException;
import com.nisum.mytime.model.Account;
import com.nisum.mytime.model.Domains;
import com.nisum.mytime.model.EmployeeRoles;
import com.nisum.mytime.repository.DomainRepo;
import com.nisum.mytime.utils.CommomUtil;
import com.nisum.mytime.utils.MyTimeUtils;


/**
 * @author Vijay
 *
 */
@Service
public class DomainServiceImpl implements DomainService {
	
	List<Domains> domainList = null;
	List<HashMap<Object, Object>> updatedDomainList = null;
	List<HashMap<String, String>> updatedEmployeeList = null;

    @Autowired
    private DomainRepo domainRepo;
    
    @Autowired
	private MongoTemplate mongoTemplate;
    
    @Autowired
   	private RoleInfoService roleInfoService;
    
    @Autowired
    private RoleMappingService roleMappingService;
   
    
    @Override
	public String addDomains(Domains d) throws MyTimeException {
        String response=null;
        int count=0;
        List<Domains> domainList=domainRepo.findByDomainNameAndAccountId(d.getDomainName(), d.getAccountId());
        List<Domains> domainListbyAccountId=domainRepo.findByAccountId(d.getAccountId());
        
        //Case sensitive logic
        for(Domains domains:domainListbyAccountId )
        {
        	if(domains.getDomainName().equalsIgnoreCase(d.getDomainName()))
        		count++;
        }
        if(count>0 || domainList.size()>0) {
        	return response="Domain already exists";
        }
        
        if (StringUtils.isEmpty(d.getDomainId()) && d.getId()==null) {
            d.setDomainId((MyTimeUtils.DOM + MyTimeUtils.ZERO_) + (getAllDomains().size() +1));
        }
        d.setStatus(MyTimeUtils.ACTIVE);
        
        if(d.getId()==null){
            response="Domain saved successfully";
        }else{
            response="Domain updated successfully";
        }
        domainRepo.save(d);
        String roleId = roleInfoService.getRole(MyTimeUtils.DOMAIN);
        roleMappingService.saveUniqueEmployeeAndRole(d.getDeliveryManagers(), roleId);
        return response;
	}
    
    @Override
    public List<HashMap<Object, Object>> getAllDomains() throws MyTimeException {

    	domainList=domainRepo.findAll();
    	updatedDomainList = new ArrayList<>();
    	
		for (Domains domain : domainList) {
			HashMap<Object, Object> domainMap = new HashMap<>();
			domainMap.put(MyTimeUtils.ID_,domain.getId());
			domainMap.put(MyTimeUtils.DOMAIN_ID, domain.getDomainId());
			domainMap.put(MyTimeUtils.DOMAIN_NAME,domain.getDomainName());
			domainMap.put(MyTimeUtils.STATUS,domain.getStatus());
			domainMap.put(MyTimeUtils.ACCOUNT_ID, domain.getAccountId());
			
            Query accountInfoQuery = new Query(Criteria.where(MyTimeUtils.ACCOUNT_ID).in(domain.getAccountId()));
            List<Account> accountList = mongoTemplate.find(accountInfoQuery, Account.class);
            
            if(accountList!=null && accountList.size()>0)
            	domainMap.put(MyTimeUtils.ACCOUNT_NAME, accountList.get(0).getAccountName());

            updatedEmployeeList = new ArrayList<>();
            List<String> employeeIds=domain.getDeliveryManagers();
            Query query = new Query(Criteria.where(MyTimeUtils.EMPLOYEE_ID).in(employeeIds));
			List<EmployeeRoles> employeeRoles = mongoTemplate.find(query, EmployeeRoles.class);
			for(EmployeeRoles employeesRole : employeeRoles){
				HashMap<String, String> employeeMap = new HashMap<>();	
				employeeMap.put(MyTimeUtils.EMPLOYEE_ID,employeesRole.getEmployeeId());
				employeeMap.put(MyTimeUtils.EMPLOYEE_NAME,employeesRole.getEmployeeName());
				updatedEmployeeList.add(employeeMap);
			}	
			domainMap.put(MyTimeUtils.DELIVERY_MANAGERS,updatedEmployeeList);
			
			updatedDomainList.add(domainMap);
		}
    	return updatedDomainList;
    }
    
    @Override
	public String updateDomain(Domains d) throws MyTimeException{
        String response = null;
       
        List<String> deliveryManagersListFromUser = null;
        List<String> deliveryManagersListFromDb = null;
        List<String> managersAddedByUser = null;
        List<String> managersDeletedByUser = null;
        Map<String, Integer> managersDomainCount = new HashMap<String,Integer>();

        Domains domainDetailsFromDb = getDomainById(d.getDomainId());
        deliveryManagersListFromUser = d.getDeliveryManagers();
        
        if (null != domainDetailsFromDb)
            deliveryManagersListFromDb = domainDetailsFromDb.getDeliveryManagers();
        
        boolean isDuplicate=duplicateCheck(d.getDomainName(), d.getAccountId(),deliveryManagersListFromDb,d.getDeliveryManagers());
        if(isDuplicate) {
        	return response="Domain already exists";
        }else{
            response="Domain updated successfully";
        }
        
        managersAddedByUser = CommomUtil.getAddedManagersList(deliveryManagersListFromDb, deliveryManagersListFromUser);
        managersDeletedByUser = CommomUtil.getDeletedManagersList(deliveryManagersListFromDb, deliveryManagersListFromUser);

        domainList = domainRepo.findAll();
        String roleId = roleInfoService.getRole(MyTimeUtils.DOMAIN);
        
        for (Domains domain : domainList) {
            List<String> employeeIds = domain.getDeliveryManagers();
            for (String eId : employeeIds) {                
                if(managersDomainCount.get(eId)!=null) 
                    managersDomainCount.put(eId, managersDomainCount.get(eId)+1);
                else
                    managersDomainCount.put(eId, 1);
            }
        }
        
        for(String managerId : managersDeletedByUser) {
            if(managersDomainCount.get(managerId)==1) {
                // Call service to delete manager
                roleMappingService.deleteRole(managerId,roleId);
            }
        }
        d.setStatus(MyTimeUtils.ACTIVE);
        domainRepo.save(d);
        roleMappingService.saveUniqueEmployeeAndRole(managersAddedByUser, roleId);
		return response;
	}
    
    
    @Override
    public WriteResult deleteDomain(String id) throws MyTimeException{
        List<String> domEmpIds=new ArrayList<String>();
        String roleId = roleInfoService.getRole(MyTimeUtils.DOMAIN);
        domainList=domainRepo.findAll();
        Query selectedDomainQuery = new Query(Criteria.where(MyTimeUtils.DOMAIN_ID).in(id).and(MyTimeUtils.STATUS).in(MyTimeUtils.ACTIVE) );
        List<Domains> selectedDomain = mongoTemplate.find(selectedDomainQuery, Domains.class);
        
        for (Domains domain : domainList) {
            List<String> employeeIds=domain.getDeliveryManagers();
            for(String eIds:employeeIds)
                domEmpIds.add(eIds);
        }
        
        for (String empId : selectedDomain.get(0).getDeliveryManagers()) {
               int occurrences = Collections.frequency(domEmpIds, empId);
               if(occurrences==1) {
                   //Service call for RoleMapping 
                   roleMappingService.deleteRole(empId,roleId);
               }
        } 
        Update update = new Update();
    	update.set(MyTimeUtils.STATUS,MyTimeUtils.IN_ACTIVE);
    	return mongoTemplate.upsert(selectedDomainQuery, update,Domains.class);
    }
    
    
    //Custom methods
    private Domains getDomainById(String id) {
         Query selectedDomainQuery = new Query(Criteria.where(MyTimeUtils.DOMAIN_ID).in(id).and(MyTimeUtils.STATUS).in(MyTimeUtils.ACTIVE) );
         List<Domains> selectedDomain = mongoTemplate.find(selectedDomainQuery, Domains.class);
         if(selectedDomain.size()==1)
             return selectedDomain.get(0);
         return null;
    }
    
    private boolean duplicateCheck(String domainName,String accountId,List<String> fromDB,List<String> fromUser)
    {
    	boolean check=false;
    	int count=0;
    	List<Domains> domainListbyAccountId=domainRepo.findByAccountId(accountId);
    	boolean deleveryManagersCheck=fromDB.toString().contentEquals(fromUser.toString());
    	List<Domains> domainList=domainRepo.findByDomainNameAndAccountId(domainName, accountId);
    	for(Domains domains:domainListbyAccountId )
        {
        	if(domains.getDomainName().equalsIgnoreCase(domainName))
        		count++;
        }
        if((domainList.size()>0 && deleveryManagersCheck) || count>1) 
        	check= true;
        return check;
    }
}