package info.bukova.isspst.services.orders;

import info.bukova.isspst.dao.RequirementItemDao;
import info.bukova.isspst.data.AddressEmb;
import info.bukova.isspst.data.JoinedItem;
import info.bukova.isspst.data.Order;
import info.bukova.isspst.data.OrderItem;
import info.bukova.isspst.data.RequirementItem;
import info.bukova.isspst.data.Workgroup;
import info.bukova.isspst.services.AbstractOwnedService;
import info.bukova.isspst.services.LazyLoader;
import info.bukova.isspst.services.settings.GlobalSettingsService;
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.Date;
import java.util.List;
public class OrderServiceImpl extends AbstractOwnedService<Order> implements
		OrderService {

	@Autowired
	private GlobalSettingsService globalSettings;

	@Autowired
	private RequirementItemDao requirementItemDao;

	@Autowired
	private SeasonService seasonService;

	@Override
	@PreAuthorize("hasPermission(this, 'PERM_ADD')")
	public Order createOrder(List<JoinedItem> items) {
		Order order = new Order();
		
		order.setAddress(new AddressEmb(globalSettings.getSettings().getMainAddress()));
		order.setDeliveryAddress(new AddressEmb(globalSettings.getSettings().getMainAddress()));
		order.setOrderDate(new Date());
		
		BigDecimal total = BigDecimal.ZERO;
		
		for (JoinedItem item : items) {
			total = total.add(item.getTotal());
			order.addItem(new OrderItem(item.getItem()));
		}
		
		order.setTotal(total);
		order.setSeason(seasonService.getActive());
		
		return order;
	}
	
	@Override
	@Transactional
	public BigDecimal totalOrderedForWorkgroup(Workgroup workgroup)
	{
		Query q = dao.getQuery("select sum(oi.total) "
				+ "from OrderItem oi join oi.reqItem ri join ri.requirement rq join rq.workgroup w "
				+ "where (ri.orderNum is not null or ri.orderNum = '') and w = :workgroup ");
		q.setParameter("workgroup", workgroup);
		return (BigDecimal) q.uniqueResult();
	}
	
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_ADD')")
	public void add(Order order) {
		order.setNumser(getNumberSerie());
		super.add(order);
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_READ')")
	public List<Order> getAll()
	{
		Query q = dao.getQuery("select o from Order o join fetch o.ownedBy");
		return filterQuery(q).list();
	}

	@LazyLoader("form")
	@Transactional
	public void lazyLoadOwnedBy(Order order)
	{
		if (order == null)
		{
			return;
		}

		Order o = dao.getById(order.getId());
		Hibernate.initialize(o.getOwnedBy());
		order.setOwnedBy(o.getOwnedBy());
	}

	@LazyLoader({ "form", "grid" })
	@Transactional
	public void lazyLoadItems(Order order)
	{
		if (order == null)
		{
			return;
		}

		Order o = dao.getById(order.getId());
		Hibernate.initialize(o.getItems());
		order.setItems(o.getItems());
	}

	@Override
	public BigDecimal calcTotalFromItem(OrderItem item)
	{
		BigDecimal total = BigDecimal.ZERO;

		if (item != null)
		{
			total = item.getQuantity().multiply(item.getUnitPrice());
		}

		return total;
	}

	@Override
	public OrderItem calcTotalInItem(OrderItem item)
	{
		OrderItem newItem = item;

		if (newItem != null)
		{
			BigDecimal total = this.calcTotalFromItem(newItem);
			newItem.setTotal(total);
		}

		return newItem;
	}

	@Override
	public OrderItem calcItemValuesFromItemTotal(OrderItem item)
	{
		OrderItem newItem = item;

		if (newItem != null)
		{
			BigDecimal quantity = newItem.getQuantity();

			if (quantity.equals(BigDecimal.ZERO))
			{
				newItem.setUnitPrice(BigDecimal.ZERO);
			}
			else
			{
				newItem.setUnitPrice(newItem.getTotal().divide(quantity, 2, BigDecimal.ROUND_HALF_UP));
			}
		}

		return newItem;
	}

	@Override
	public BigDecimal calcSumTotalFromItems(List<OrderItem> items)
	{
		BigDecimal sumTotal = BigDecimal.ZERO;

		if (items != null)
		{
			for (OrderItem item : items)
			{
				if (item != null)
				{
					BigDecimal total = item.getTotal();

					if (total != null)
					{
						sumTotal = sumTotal.add(total);
					}
				}
			}
		}

		return sumTotal;
	}

	protected void setApprovedItems(Order order, boolean orderedChanged)
	{
		if (orderedChanged)
		{
			for (OrderItem item : order.getItems())
			{
				RequirementItem rItem = item.getReqItem();

				if (rItem != null)
				{
					rItem.setOrderNum(order.isOrdered() ? order.getNumser() : null);
					requirementItemDao.modify(rItem);
				}
			}
		}
	}

	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_ADD')")
	public void addApprovedItems(Order order, boolean orderedChanged)
	{
		this.add(order);
		this.setApprovedItems(order, orderedChanged);
	}

	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_EDIT') or hasPermission(#entity, this.getUpdateEntityPermission())")
	public void updateApprovedItems(Order order, boolean orderedChanged)
	{
		this.setApprovedItems(order, orderedChanged);
		super.update(order);
	}

	@Override
	@Transactional
	@PreAuthorize("hasPermission(this, 'PERM_DELETE') or hasPermission(#entity, this.getDeleteEntityPermission())")
	public void delete(Order order) {
		for (OrderItem item : order.getItems())
		{
			RequirementItem rItem = item.getReqItem();
			
			if (rItem != null)
			{
				rItem.setOrderNum(null);
				requirementItemDao.modify(rItem);
			}
		}
		
		super.delete(order);
	}
}
