package eu.dnetlib.goldoa.service;

import eu.dnetlib.goldoa.domain.Budget;
import eu.dnetlib.goldoa.domain.Organization;
import eu.dnetlib.goldoa.domain.PersonManagerException;
import eu.dnetlib.goldoa.domain.User;
import eu.dnetlib.goldoa.service.dao.BudgetDAO;
import eu.dnetlib.goldoa.service.utils.EmailUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;

/*
 * Created by antleb on 4/2/15.
*/

@Transactional
@Service("budgetManager")
public class BudgetManagerImpl implements BudgetManager {

	@Autowired private BudgetDAO budgetDAO;
	@Autowired private UserManager userManager;
	@Autowired private OrganizationManager organizationManager;
	@Autowired private PublisherManager publisherManager;
	@Autowired private ExecutorService executorService;
	@Autowired private EmailUtils emailUtils;

	@Override
	public Budget saveBudget(final Budget budget) {

		if(budget.getId() == null){
			//getRequestId
			budget.setId("B-" + new SimpleDateFormat("yyyyMMdd-").format(new Date()) + budgetDAO.getRequestId());
			/*budget.setDate(new Date());
			budget.setRemaining(budget.getAmountGranted());*/
		}
		budgetDAO.saveBudget(budget);
		return budget;
	}

	@Override
	public Budget submitBudgetRequest(final Budget budget) {
		budget.setStatus(Budget.Status.SUBMITTED);
		saveBudget(budget);
		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {

					List<User> moderators = userManager.getModerators();
					emailUtils.sendUserNewBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorNewBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		return budget;
	}

	@Override
	public Budget getBudget(String budgetId) {
		return budgetDAO.getBudget(budgetId);
	}

	@Override
	public List<Budget> getBudgets() {
		return budgetDAO.getBudgets();		
	}

	@Override
	public List<Budget> getBudgetsForUser(String user_email) {
		return budgetDAO.getBudgetsForUser(user_email);
	}

	@Override
	public List<Budget> getBudgetsForPublisher(String publisherEmail) {
		return budgetDAO.getBudgetsForPublisher(publisherEmail);
	}

	@Override
	public List<Budget> getBudgetsForAccounting() {
		return budgetDAO.getBudgetsForAccounting();
	}

	@Override
	public List<Budget> getBudgetsForOrganization(List<String> organizationIds) {
		return budgetDAO.getBudgetsForOrganization(organizationIds);
	}

	@Override
	public void initiallyApproveBudgetRequest(final String budgetId, String comment, String email) {
		budgetDAO.initiallyApproveBudget(budgetId);
		User user = null;
		try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}
		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					List<User> moderators = userManager.getModerators();
					Budget budget = budgetDAO.getBudget(budgetId);
					emailUtils.sendUserAcceptedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorAcceptedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void approveBudgetRequest(final String budgetId, String comment, float amountGranted, String email) {
		budgetDAO.approveBudget(budgetId, amountGranted);

		User user = null;
		try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}

		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Budget budget = budgetDAO.getBudget(budgetId);
					List<User> moderators = userManager.getModerators();
					emailUtils.sendUserAcceptedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorAcceptedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void rejectBudgetRequest(final String budgetId, String comment, String email) {
		budgetDAO.rejectBudget(budgetId);
		//budgetDAO.updateBudgetComment(budgetId, comment);

        User user = null;
        try {
            user = userManager.getByEmail(email);
        } catch (PersonManagerException e) {
            e.printStackTrace();
        }

        budgetDAO.saveComment(budgetId, user , comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					List<User> moderators = userManager.getModerators();
					Budget budget = budgetDAO.getBudget(budgetId);
					emailUtils.sendUserRejectedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorRejectedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void processingPayment(final String budgetId, String comment, String email) {
		budgetDAO.processingBudget(budgetId);

		User user = null;
		/*try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}
*/
		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					List<User> moderators = userManager.getModerators();
					Budget budget = budgetDAO.getBudget(budgetId);
					emailUtils.sendUserRejectedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorRejectedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void denyPayment(final String budgetId, String comment, String email) {
		budgetDAO.accountingDeniedBudget(budgetId);

		User user = null;
		try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}

		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					List<User> moderators = userManager.getModerators();
					Budget budget = budgetDAO.getBudget(budgetId);
					emailUtils.sendUserRejectedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorRejectedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void onHoldPayment(final String budgetId, String comment, String email) {
		budgetDAO.accountingOnHoldBudget(budgetId);

		User user = null;
		try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}

		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					List<User> moderators = userManager.getModerators();
					Budget budget = budgetDAO.getBudget(budgetId);
					emailUtils.sendUserRejectedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorRejectedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void budgetPaid(final String budgetId, String comment, String email) {
		budgetDAO.accountingPaidBudget(budgetId);

		User user = null;
		try {
			user = userManager.getByEmail(email);
		} catch (PersonManagerException e) {
			e.printStackTrace();
		}

		budgetDAO.saveComment(budgetId, user, comment, null);

		executorService.submit(new Runnable() {
			@Override
			public void run() {
				try {
					Budget budget = budgetDAO.getBudget(budgetId);
					List<User> moderators = userManager.getModerators();
					emailUtils.sendUserRejectedBudgetEmail(budget);

					for (User moderator : moderators)
						emailUtils.sendModeratorRejectedBudgetEmail(moderator, budget);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void uploadInitialContract(String budgetId, String contentType, InputStream inputStream) {
		budgetDAO.uploadInitialContract(budgetId, contentType, inputStream);
	}

	@Override
	public void uploadBeneficiaryContract(String budgetId, String contentType, InputStream inputStream) {
		budgetDAO.uploadBeneficiaryContract(budgetId, contentType, inputStream);
	}

	@Override
	public void uploadSignedContract(String budgetId, String contentType, InputStream inputStream) {
		budgetDAO.uploadSignedContract(budgetId, contentType, inputStream);
	}

	@Override
	public void uploadBankReceipt(String budgetId, String contentType, InputStream inputStream) {
		budgetDAO.uploadBankReceipt(budgetId, contentType, inputStream);
	}

	@Override
	public Budget getForRequest(String organizationId, String publisherEmail) {
		List<Budget> budgets;
		Budget res = null;

		if (organizationId != null) {
			budgets = getBudgetsForOrganization(Arrays.asList(organizationId));

			for (Budget budget : budgets) {
				if (isValid(budget)) {
					res = budget;

					break;
				}
			}
		} else if (publisherEmail != null) {
			budgets = getBudgetsForPublisher(publisherEmail);

			for (Budget budget : budgets) {
				if (isValid(budget)) {
					res = budget;

					break;
				}
			}
		}

		return res;
	}

	private boolean isValid(Budget budget) {
		return budget.getStatus().getCode() == Budget.Status.ACCOUNTING_PAID.getCode();

	}

	private Budget.Status getStatus(int statusCode) {
		return Budget.Status.forStatus(statusCode);
	}

	public Organization getOrganizationForBudget(String budgetID){
		return budgetDAO.getOrganizationForBudget(budgetID);
	}
}
