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.AccountInfo;
import com.nisum.mytime.model.Domains;
import com.nisum.mytime.model.EmployeeRoles;
import com.nisum.mytime.repository.DomainRepo;

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;
        List<Domains> domainList=domainRepo.findByDomainNameAndAccountId(d.getDomainName(), d.getAccountId());
       
        if(domainList.size()>0) {
            response="Domain already exists";
            return response;
        }
        
        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 succesfully";
        }else{
            response="Domain updated succesfully";
        }
        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<>();
    	Map<String, String> accountMap = new HashMap<String, String>();
    	
		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());

            String accountId=domain.getAccountId();
            Query accountInfoQuery = new Query(Criteria.where("accountId").in(accountId));
            List<AccountInfo> accountList = mongoTemplate.find(accountInfoQuery, AccountInfo.class);
            accountMap.put("AccountId", accountId);
            accountMap.put("AccountName", accountList.get(0).getAccountName());
            domainMap.put("AccountInfo", accountMap);

            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();
        
        managersAddedByUser = getAddedManagersList(deliveryManagersListFromDb, deliveryManagersListFromUser);
        managersDeletedByUser = 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 List<String> getAddedManagersList(List<String> fromDb, List<String> fromUser) {
        List<String> addedManagers = new ArrayList<String>();
        if (fromDb != null)
            for (String managerFromUser : fromUser) {
                if (!fromDb.contains(managerFromUser))
                    addedManagers.add(managerFromUser);
            }
        return addedManagers;
    }
    
    private List<String> getDeletedManagersList(List<String> fromDb, List<String> fromUser) {
        List<String> deletedManager = new ArrayList<String>();
        if (fromDb != null)
            for (String managerFromDb : fromDb) {
                if (!fromUser.contains(managerFromDb))
                    deletedManager.add(managerFromDb);
            }
        return deletedManager;
    }
}