package info.bukova.isspst.services.invoicing;

import info.bukova.isspst.Constants;
import info.bukova.isspst.data.Invoicing;
import info.bukova.isspst.data.InvoicingItem;
import info.bukova.isspst.data.Requirement;
import info.bukova.isspst.data.Season;
import info.bukova.isspst.data.Workgroup;
import info.bukova.isspst.services.AbstractOwnedService;
import info.bukova.isspst.services.LazyLoader;
import info.bukova.isspst.services.settings.SeasonService;
import org.hibernate.Hibernate;
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.math.BigDecimal;
import java.util.List;

public class InvoicingServiceImpl extends AbstractOwnedService<Invoicing> implements
		InvoicingService {

	@Autowired
	private SeasonService seasonService;

	@Override
	@Transactional
	public BigDecimal totalInvoicedForWorkgroup(Workgroup workgroup) {
		return totalInvoicedForWorkgroupAndSeason(workgroup, seasonService.getActive());
	}

	@Override
	@Transactional
	public BigDecimal totalInvoicedForWorkgroupAndSeason(Workgroup workgroup, Season season) {
		Query q = dao.getQuery("select sum(inv.totalInvoiced) "
				+ "from Invoicing inv join inv.requirement rq join rq.workgroup w "
				+ "where w = :workgroup and rq.season = :season");
		q.setParameter("workgroup", workgroup);
		q.setParameter("season", season);
		return (BigDecimal) q.uniqueResult();
	}

	@Override
	@Transactional
	@LazyLoader("form")
	public void loadReqItems(Invoicing invoicing) {
		Invoicing inv = getById(invoicing.getId());
		Hibernate.initialize(inv.getRequirement().getItems());
		invoicing.getRequirement().setItems(inv.getRequirement().getItems());
	}

	@Override
	@Transactional
	@LazyLoader({"form", "grid"})
	public void loadItems(Invoicing invoicing) {
		Invoicing inv = getById(invoicing.getId());
		Hibernate.initialize(inv.getItems());
		invoicing.setItems(inv.getItems());
	}

	@Transactional
	@LazyLoader
	public void loadReqAuth(Invoicing invoicing) {
		Invoicing inv = getById(invoicing.getId());
		Hibernate.initialize(inv.getRequirement().getAuthorization());
		invoicing.getRequirement().setAuthorization(inv.getRequirement().getAuthorization());
	}

	@Override
	public void calculate(Invoicing invoicing) {
		BigDecimal total = BigDecimal.ZERO;
		
		for (InvoicingItem item : invoicing.getItems()) {
			total = total.add(item.getAmount());
		}
		
		invoicing.setTotalInvoiced(total);
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getAll() {
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy order by rq.numser");
		return q.list();
	}
	
	@Transactional
	@LazyLoader("form")
	public void loadOwnedBy(Invoicing invoice) {
		Invoicing inv = getById(invoice.getId());
		Hibernate.initialize(inv.getRequirement().getOwnedBy());
		invoice.getRequirement().setOwnedBy(inv.getRequirement().getOwnedBy());
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getPendingList()
	{
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where (inv.completed Is Null or inv.completed = false) order by rq.numser");
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getArchiveList()
	{
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where inv.completed = true order by rq.numser");
		return q.list();
	}

	@Override
	@Transactional
	public Invoicing getForRequirement(Requirement req) {
		Query query = dao.getQuery("select invoice from Invoicing invoice join invoice.requirement rq where rq.id = :reqId");
		query.setParameter("reqId", req.getId());

		return (Invoicing) query.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getMaterialPendingList() {
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where (inv.completed Is Null or inv.completed = false) and (rq.kind = :kind) order by rq.numser desc");
		q.setParameter("kind", Constants.REQ_TYPE_MATERIAL);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getMaterialArchiveList() {
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where (inv.completed = true) and (rq.kind = :kind) order by rq.numser desc");
		q.setParameter("kind", Constants.REQ_TYPE_MATERIAL);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getServicesPendingList() {
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where (inv.completed Is Null or inv.completed = false) and (rq.kind = :kind) order by rq.numser desc");
		q.setParameter("kind", Constants.REQ_TYPE_SERVICES);
		return q.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Invoicing> getServicesArchiveList() {
		Query q = dao.getQuery("select inv from Invoicing as inv join fetch inv.requirement rq join fetch rq.ownedBy where (inv.completed = true) and (rq.kind = :kind) order by rq.numser desc");
		q.setParameter("kind", Constants.REQ_TYPE_SERVICES);
		return q.list();
	}
}
