/*******************************************************************************
 * Copyright 2Fi Business Solutions Ltd.
 *
 * This code is copyrighted. Under no circumstances should any party, people,
 * or organization should redistribute any portions of this code in any form,
 * either verbatim or through electronic media, to any third parties, unless
 * under explicit written permission by 2Fi Business Solutions Ltd.
 ******************************************************************************/
package com.ffii.tbms.order.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffii.core.dao.JdbcDao;
import com.ffii.core.utils.MapUtils;
import com.ffii.core.utils.Params;
import com.ffii.core.utils.SecurityUtils;
import com.ffii.core.web.AbstractService;
import com.ffii.tbms.log.LogUtils;
import com.ffii.tbms.log.service.AuditLogService;
import com.ffii.tbms.order.Payment;
import com.ffii.tbms.order.dao.PaymentDao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Patrick
 */
@Service
public class PaymentService extends AbstractService {

	@Autowired
	private JdbcDao jdbcDao;

	@Autowired
	private PaymentDao paymentDao;

	@Autowired
	private AuditLogService auditLogService;

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	public Integer saveOrUpdate(Payment instance) {
		return paymentDao.saveOrUpdate(instance);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = true)
	public Payment find(Integer id) {
		return paymentDao.find(id);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = true)
	public List<Map<String, Object>> search(Map<String, Object> args) {

		StringBuilder sql = new StringBuilder(
			" SELECT p.id, "
			+" p.orderId, "
			+" p.date, "
			+" p.amount, "
			+" p.method, "
			+" p.refNo "
			+" FROM payment p "
			+" WHERE p.deleted = 0 ");

		if (args != null) {
			if (args.containsKey("orderId"))
				sql.append(" AND p.orderId = :orderId ");
		}

		sql.append(" ORDER BY p.id ");

		return jdbcDao.queryForList(sql.toString(), args);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = true)
	public Map<String, Object> queryForMap(Integer id) {
		String sql = "SELECT * FROM payment p WHERE p.id = :id";

		return jdbcDao.queryForMap(sql, MapUtils.toHashMap(Params.ID, id));
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	public void log(String action, int id, Payment newRecord, Payment oldRecord)throws JsonProcessingException {
		Map<String, Object> data = new HashMap<>();
		Map<String, Object> compare = LogUtils.compare(newRecord, oldRecord);
		data = (Map<String, Object>)compare.get(LogUtils.DIFF);
		log(action, id, data, newRecord);
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	public void log(String action, int id, Map<String, Object> data, Payment newRecord)throws JsonProcessingException {
		if(data.size()<=0) return;
		ObjectMapper mapper = new ObjectMapper();
		auditLogService.save("payment",
							id,
							SecurityUtils.getUser().getId(),
							new Date(),
							action,
							mapper.writeValueAsString(data),
							newRecord.getOrderId(),
							"orders");
	}

	@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
	public void log(String action, int id, Payment newRecord)throws JsonProcessingException {
		Map<String, Object> data = LogUtils.filter(LogUtils.objectToMap(newRecord));
		log(action, id, data, newRecord);
	}

}
