package info.bukova.isspst.services.requirement;

import info.bukova.isspst.Constants;
import info.bukova.isspst.data.NumberSeries;
import info.bukova.isspst.data.RequirementState;
import info.bukova.isspst.data.TripBill;
import info.bukova.isspst.data.TripBillApproval;
import info.bukova.isspst.data.TripRequirement;
import info.bukova.isspst.data.User;
import info.bukova.isspst.mail.MailMessage;
import info.bukova.isspst.mail.Mailer;
import info.bukova.isspst.mail.MessageBuilder;
import info.bukova.isspst.services.LazyLoader;
import info.bukova.isspst.services.settings.GlobalSettingsService;
import info.bukova.isspst.services.tripbill.TripBillApprovalService;
import info.bukova.isspst.services.tripbill.TripBillService;
import info.bukova.isspst.services.users.UserService;
import org.hibernate.Hibernate;
import org.hibernate.LazyInitializationException;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

public class TripRequirementServiceImpl extends RequirementBaseServiceImpl<TripRequirement>
		implements TripRequirementService, RequirementBaseService<TripRequirement> {
	
	@Autowired
	private RequirementTypeService reqTypeService;
	@Autowired
	private TripBillService tripBillService;
	@Autowired
	private TripBillApprovalService tripBillApprovalService;
	@Autowired
	private Mailer mailer;
	@Autowired
	private MessageBuilder messageBuilder;
	@Autowired
	private GlobalSettingsService settingsService;
	@Autowired
	private UserService userService;

	@Override
	protected TripRequirement createEntity() {
		TripRequirement tr = new TripRequirement();
		tr.setReqDate(new Date());
		tr.setType(reqTypeService.getTypeById(Constants.REQTYPE_BUSINESSTRIP));
		tr.setState(RequirementState.NEW);

		return tr;
	}

	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_EDIT') or hasPermission(#entity, this.getUpdateEntityPermission())")
	public void update(TripRequirement entity) {
		if (entity.getState() == RequirementState.APPROVED) {
			for (TripBill bill : getBills(entity)) {
				TripBill newBill = tripBillService.createTripBill(entity);
				bill.getBillItems().clear();
				bill.getBillItems().addAll(newBill.getBillItems());
				TripBillApproval approval = bill.getApproval();

				if (approval != null) {
					tripBillApprovalService.delete(approval);
				}

				bill.setApproval(null);
				tripBillService.calculate(bill);
				tripBillService.update(bill);
			}
		}

		super.update(entity);
	}

	@Override
	protected void postAdd(TripRequirement entity) {
		super.postAdd(entity);
		sendMailToPassengers(entity, settingsService.getSettings().getReqPassenger());
	}

	private void sendMailToPassengers(TripRequirement entity, MailMessage messageTemplate) {
		if (entity.getBillForPassengers() != null && !entity.getPassengers().isEmpty() && messageTemplate != null) {
			MailMessage message = messageBuilder.buildMessage(messageTemplate, entity);
			message.setFrom(userService.getCurrent().getEmail());
			message.setTo(userService.getEmailsForSend(entity.getPassengers()));
			mailer.send(message);
		}
	}

	@Override
	@Transactional
	@LazyLoader("form")
	public void loadPassangers(TripRequirement entity) {
		try {
			if (entity.getPassengers() == null) {
				throw new LazyInitializationException("");
			}
			
			entity.getPassengers().size();
		} catch (LazyInitializationException ex) {
			TripRequirement e = dao.getById(entity.getId());
			e.getPassengers().size();
			entity.setPassengers(e.getPassengers());	
		}
	}

	@Override
	@Transactional
	public TripBill getTripBill(TripRequirement requirement) {
		Query q = dao.getQuery("from TripBill tb where tb.requirement = :req");
		q.setParameter("req", requirement);
		List<TripBill> result = q.list();

		if (result.size() > 0) {
			return result.get(0);
		}

		return null;
	}

	@Override
	@Transactional
	public List<TripBill> getBills(TripRequirement entity) {
		Query q = queryDao.getQuery("from TripBill bill where bill.requirement = :req");
		q.setParameter("req", entity);
		return q.list();
	}

	@Transactional
	@LazyLoader("form")
	public void loadAttachments(TripRequirement entity) {
		TripRequirement e = dao.getById(entity.getId());
		Hibernate.initialize(e.getAttachedFiles());
		entity.setAttachedFiles(e.getAttachedFiles());
	}

	@Override
	protected void postApprove(TripRequirement entity) {
		if (entity.getState() != RequirementState.APPROVED) {
			return;
		}

		List<TripBill> billList = getBills(entity);
		boolean hasOwned = false;

		for (TripBill tb : billList) {
			if (tb.getOwnedBy().equals(entity.getOwnedBy())) {
				hasOwned = true;
				break;
			}
		}

		if (!hasOwned) {
			TripBill bill = tripBillService.createTripBill(entity);
			tripBillService.add(bill);
			bill.setOwnedBy(entity.getOwnedBy());
			tripBillService.update(bill);
		}

		if (entity.getBillForPassengers() != null && entity.getBillForPassengers()) {
			for (User u : entity.getPassengers()) {
				if (canCreateBill(entity, u, billList)) {
					TripBill passBill = tripBillService.createPassengersBill(entity);
					tripBillService.add(passBill);
					passBill.setOwnedBy(u);
					tripBillService.update(passBill);
				}
			}

			sendMailToPassengers(entity, settingsService.getSettings().getConfReqTripPassenger());
		}
	}

	private boolean canCreateBill(TripRequirement req, User owner, List<TripBill> bills) {
		if (owner.equals(req.getOwnedBy())) {
			return false;
		}

		for (TripBill tb : bills) {
			if (tb.getOwnedBy().equals(owner)) {
				return false;
			}
		}

		return true;
	}

	@Override
	protected String getNumberSerie() {
		String currentNumber = "";
		
		if (getNumberSeriesService() != null)
		{
			NumberSeries ns = getNumberSeriesService().getNumberSerie(Constants.MOD_REQUIREMENTS);
			
			if (ns != null)
			{
				currentNumber = ns.getCurrentNumber();
				getNumberSeriesService().increase(ns);
			}
		}
		
		return currentNumber;
	}

}
