package com.nisum.mytime.service;

import java.util.ArrayList;
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.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.nisum.mytime.exception.handler.MyTimeException;
import com.nisum.mytime.model.AccountInfo;
import com.nisum.mytime.model.EmployeeRoles;
import com.nisum.mytime.repository.AccountInfoRepo;
import com.nisum.mytime.utils.MyTimeUtils;

@Service
public class AccountServiceImpl implements AccountService {

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private AccountInfoRepo accountRepo;

	@Override
	public AccountInfo addAccount(AccountInfo account) throws MyTimeException {
		return accountRepo.save(account);
	}

	@Override
	public List<AccountInfo> getAccounts() throws MyTimeException {
		return accountRepo.findAll();
	}

	@Override
	public List<Map<Object, Object>> getAccountsList() throws MyTimeException {
		List<Map<Object, Object>> updatedAccountList = new ArrayList<>();
		List<Map<String, String>> updatedEmployeeList = null;
		for (AccountInfo account : getAccountInfo()) {
			updatedEmployeeList = new ArrayList<>();
			for (EmployeeRoles employeesRole : getEmployeeDetails(account)) {
				updatedEmployeeList.add(getEmployeeDetails(employeesRole));
			}
			updatedAccountList.add(getAccuntDetails(account, updatedEmployeeList));
		}
		return updatedAccountList;
	}

	// fetching the employee details using employeeId.
	private List<EmployeeRoles> getEmployeeDetails(AccountInfo account) {
		List<EmployeeRoles> employeeRoles = mongoTemplate.find(
				new Query(Criteria.where(MyTimeUtils.EMPLOYEE_ID).in(account.getDeliveryManagers())),
				EmployeeRoles.class);
		return employeeRoles;
	}

	// fetching the active account details.
	private List<AccountInfo> getAccountInfo() {
		List<AccountInfo> accountList = mongoTemplate
				.find(new Query(Criteria.where(MyTimeUtils.STATUS).is(MyTimeUtils.ACTIVE)), AccountInfo.class);
		return accountList;
	}

	private HashMap<String, String> getEmployeeDetails(EmployeeRoles employeesRole) {
		HashMap<String, String> employeeDetails = new HashMap<>();
		employeeDetails.put(MyTimeUtils.EMPLOYEE_ID, employeesRole.getEmployeeId());
		employeeDetails.put(MyTimeUtils.EMPLOYEE_NAME, employeesRole.getEmployeeName());
		return employeeDetails;
	}

	private Map<Object, Object> getAccuntDetails(AccountInfo account, List<Map<String, String>> updatedEmployeeList) {
		Map<Object, Object> accountDetails = new HashMap<>();
		accountDetails.put(MyTimeUtils.ACC_ID, account.getId());
		accountDetails.put(MyTimeUtils.ACCOUNT_ID, account.getAccountId());
		accountDetails.put(MyTimeUtils.ACCOUNT_NAME, account.getAccountName());
		accountDetails.put(MyTimeUtils.STATUS, account.getStatus());
		accountDetails.put(MyTimeUtils.CLIENT_ADDRESS, account.getClientAddress());
		accountDetails.put(MyTimeUtils.INDUSTRY_TYPE, account.getIndustryType());
		accountDetails.put(MyTimeUtils.DELIVERY_MANAGERS, updatedEmployeeList);
		return accountDetails;
	}

	// updating the status to "InActive".
	public AccountInfo deleteAccount(String accountId) throws MyTimeException {
		Query query = new Query(Criteria.where(MyTimeUtils.ACCOUNT_ID).is(accountId));
		Update update = new Update();
		update.set(MyTimeUtils.STATUS, MyTimeUtils.IN_ACTIVE);
		FindAndModifyOptions options = new FindAndModifyOptions();
		options.upsert(true);
		return mongoTemplate.findAndModify(query, update, options, AccountInfo.class);
	}

}
