package com.nisum.myteam.service.impl;

import com.nisum.myteam.exception.handler.MyTeamException;
import com.nisum.myteam.model.Reports;
import com.nisum.myteam.model.dao.Account;
import com.nisum.myteam.model.dao.Employee;
import com.nisum.myteam.model.dao.Project;
import com.nisum.myteam.model.dao.Resource;
import com.nisum.myteam.model.vo.ReportVo;
import com.nisum.myteam.model.vo.ResourceVO;
import com.nisum.myteam.service.IReportService;
import com.nisum.myteam.statuscodes.ResourceStatus;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ReportService implements IReportService {
	
    private static final String Shadow = "Shadow";

	private static final String Reserved = "Reserved";

    @Autowired
    private EmployeeService employeeService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private FunctionalGroupService functionalGroupService;

    public ReportVo getBarChartReport(String byType) throws MyTeamException {
        ReportVo reportVo = new ReportVo();

        if(byType.equals("FunctionalGroup")) {
            functionalGroupService.getAllFunctionalGroups().forEach(f -> reportVo.getCategoriesList().add(f.getName()));
        } else {
            accountService.getAllAccounts().forEach(a -> reportVo.getCategoriesList().add(a.getAccountName()));
        }

        Map<String,Object> billableData = new HashMap();
        Map<String,Object> nonBillableData = new HashMap();
        Map<String,Object> traineeData = new HashMap();
        List<Object> billableCount = new ArrayList<>();
        List<Object> nonBillableCount = new ArrayList<>();
        List<Object> traineeCount = new ArrayList<>();
        billableData.put("name","Billable");
        nonBillableData.put("name","Non-Billable");
        traineeData.put("name", "Trainee");
        for(String category:reportVo.getCategoriesList()){
            Map<String,Object> billableObj = new HashMap();
            Map<String,Object> nonbillableObj = new HashMap();
            //     Map<String,Object> traineeObj = new HashMap();
            Integer billableC=0;
            Integer nonBillableC=0;
            Integer traineeC=0;
            //         float traineePer;
            float billper;
            float nonBillPer;
            List<Employee> employeeList = new ArrayList<>();
            if(byType.equals("FunctionalGroup")) {
                employeeList = getEmployeesByFunctionalGroup(category);
            } else {
                employeeList = getEmployeeByAccounts(category);
            }
//            .getAllEmployees().stream().
//                    filter(e -> e.getFunctionalGroup().equals(functionalGroup)).collect(Collectors.toList());
            for(Employee employee:employeeList){
                Resource resource = resourceService.getLatestResourceByEmpId(employee.getEmployeeId());
                if(resource!=null && resource.getBillableStatus().equals("Billable")){
                    billableC++;
                }else if(resource!=null && resource.getBillableStatus().equals("Trainee")) {
                    traineeC++;
                } else{
                    nonBillableC++;
                }
            }
            billper = ((billableC / (float)(employeeList.size() - traineeC))*100);
            nonBillPer = nonBillableC /(float) (employeeList.size()-traineeC)*100;
//            traineePer = traineeC / (float) employeeList.size()*100;
            billableObj.put("percent", billper);
            billableObj.put("y", billableC);
            nonbillableObj.put("percent", nonBillPer);
            nonbillableObj.put("y", nonBillableC);
//            traineeObj.put("percent", traineePer);
//            traineeObj.put("y", traineeC);
            billableCount.add(billableObj);
            nonBillableCount.add(nonbillableObj);
            traineeCount.add(traineeC);
        }
        billableData.put("data",billableCount);
        nonBillableData.put("data",nonBillableCount);
        traineeData.put("data", traineeCount);
        reportVo.getSeriesDataList().add(billableData);
        reportVo.getSeriesDataList().add(nonBillableData);
        reportVo.getSeriesDataList().add(traineeData);
    return reportVo;
    }

    private List<Employee> getEmployeesByFunctionalGroup(String functionalGroup){
        return employeeService.getEmployeesByFunctionalGrp(functionalGroup);
    }

    private List<Employee> getEmployeeByAccounts(String accountName){
        List<Employee> employeeList = new ArrayList<>();
        List<Project> projects = projectService.getProjectsByAccountId(accountService.getAccountByName(accountName).getAccountId());
        projects.stream().forEach(p -> {
        resourceService.getResourceByProjectId(p.getProjectId()).stream().filter(r -> r.getBillingEndDate().after(new Date())).
                forEach(r ->employeeList.add(employeeService.getEmployeeById(r.getEmployeeId())));
        });
        return employeeList;
    }

	@Override
	public List<Reports> getEmployeeDetailsByFGAndBillability(String fGroup, String billableStatus)
			throws MyTeamException {		
		List<Employee> employeesByFG=employeeService.getEmployeesByFunctionalGrp(fGroup);
		return resultantEmployeeWithBillability(employeesByFG,billableStatus);
	}
	
	@Override
	public List<Reports> getEmployeeDetailsByAccountBillability(String accountName, String billabilityStatus)
			throws MyTeamException {
		
		return resultantEmployeeWithBillability(getEmployeeByAccounts(accountName),billabilityStatus);
	}

	private List<Reports> resultantEmployeeWithBillability(List<Employee> employees,
			String billableStatus) {
		List<Reports> resultantEmployees=new ArrayList<Reports>();
		for(Employee employee:employees) {
			Resource resourceObj=resourceService.getLatestResourceByEmpId(employee.getEmployeeId());
			if(resourceObj.getBillableStatus().equals(billableStatus) ||( billableStatus.equals("Non-Billable") && (resourceObj.getBillableStatus().equals(Shadow)||resourceObj.getBillableStatus().equals(Reserved)))) {
				resultantEmployees.add(mappingReports(employee,resourceObj));	
			}
		}
		return resultantEmployees;		
	}
	
	private Reports  mappingReports(Employee employee,Resource resourceObj){
		Reports Reports=new Reports();
		Project project=projectService.getProjectByProjectId(resourceObj.getProjectId());
		Reports.setEmployeeId(resourceObj.getEmployeeId());
		Reports.setEmployeeName(employee.getEmployeeName());
		Reports.setEmailId(employee.getEmailId());
		Reports.setProjectName(project.getProjectName());
		Reports.setBillingStartDate(resourceObj.getBillingStartDate());
		Reports.setBillableStatus(resourceObj.getBillableStatus());
		Reports.setBillingEndDate(resourceObj.getBillingEndDate());
		Reports.setFunctionalGroup(employee.getFunctionalGroup());	
		return Reports;
	 }

	@Override
	public Project getProjectById(String projectId) {
		return projectService.getProjectByProjectId(projectId);
	}

}
