package com.jasamedika.medifirst2000.service.impl;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;

import com.jasamedika.medifirst2000.constants.Master;
import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.IndikatorKinerjaJabatanDao;
import com.jasamedika.medifirst2000.dao.LogbookKinerjaDao;
import com.jasamedika.medifirst2000.dao.LoggingUserDao;
import com.jasamedika.medifirst2000.entities.IndikatorKinerja;
import com.jasamedika.medifirst2000.entities.IndikatorKinerjaJabatan;
import com.jasamedika.medifirst2000.entities.Jabatan;
import com.jasamedika.medifirst2000.entities.LoggingUser;
import com.jasamedika.medifirst2000.entities.LoginUser;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.IndikatorKinerjaJabatanService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.vo.IndikatorKinerjaJabatanVO;
import com.jasamedika.medifirst2000.vo.IndikatorKinerjaVO;
import com.jasamedika.medifirst2000.vo.JabatanVO;

@Service("IndikatorKinerjaJabatanService")
public class IndikatorKinerjaJabatanServiceImpl extends BaseVoServiceImpl implements IndikatorKinerjaJabatanService {

	@Autowired
	private BaseConverterImpl<IndikatorKinerjaJabatanVO, IndikatorKinerjaJabatan> indikatorJabatanConverter;

	@Autowired
	private BaseConverterImpl<IndikatorKinerjaVO, IndikatorKinerja> indikatorConverter;

	@Autowired
	private BaseConverterImpl<JabatanVO, Jabatan> jabatanConverter;

	@Autowired
	private LogbookKinerjaDao logbookKinerjaDao;

	@Autowired
	private IndikatorKinerjaJabatanDao indikatorKinerjaJabatanDao;

	@Autowired
	private LoggingUserDao loggingUserDao;

	public void addLoggingUser(Integer idLoginUser, String idReferensi, String keterangan) {
		LoggingUser loggingUser = new LoggingUser();
		LoginUser loginUser = new LoginUser();

		loggingUser.setKdProfile((short) 0);
		loggingUser.setStatusEnabled(true);
		loggingUser.setTanggal(new Date());
		loginUser.setId(idLoginUser);
		loggingUser.setLoginUser(loginUser);
		loggingUser.setJenisLog("Mapping Indikator Kinerja - Jabatan");
		loggingUser.setReferensiId(idReferensi);
		loggingUser.setReferensi("sdm_indikatorkinerja_t");
		loggingUser.setKeterangan(keterangan);

		loggingUserDao.save(loggingUser);
	}

	public void addAllLoggingUser(List<Map<String, Object>> listLog) {
		List<LoggingUser> listLoggingUser = new ArrayList<>();
		Date now = new Date();

		for (Map<String, Object> mapLog : listLog) {
			LoggingUser loggingUser = new LoggingUser();
			LoginUser loginUser = new LoginUser();

			loggingUser.setKdProfile((short) 0);
			loggingUser.setStatusEnabled(true);
			loggingUser.setTanggal(now);
			loginUser.setId(Integer.valueOf(mapLog.get("idLoginUser").toString()));
			loggingUser.setLoginUser(loginUser);
			loggingUser.setJenisLog("Mapping Indikator Kinerja - Jabatan");
			loggingUser.setReferensiId(mapLog.get("idReferensi").toString());
			loggingUser.setReferensi("sdm_indikatorkinerja_t");
			loggingUser.setKeterangan(mapLog.get("keterangan").toString());
			listLoggingUser.add(loggingUser);
		}

		loggingUserDao.save(listLoggingUser);
	}

	@Override
	public IndikatorKinerjaJabatanVO add(IndikatorKinerjaJabatanVO vo) throws JpaSystemException, ServiceVOException {
		Jabatan jabatan = jabatanConverter.transferVOToModel(vo.getJabatan(), new Jabatan());
		IndikatorKinerja indikator = indikatorConverter.transferVOToModel(vo.getIndikatorKinerja(),
				new IndikatorKinerja());
		IndikatorKinerjaJabatan indikatorJabatan = indikatorJabatanConverter.transferVOToModel(vo,
				new IndikatorKinerjaJabatan());

		indikatorJabatan.setJabatan(jabatan);
		indikatorJabatan.setIndikatorKinerja(indikator);
		indikatorJabatan.setTanggalPembaharuanData(new Date());
		IndikatorKinerjaJabatan resultModel = indikatorKinerjaJabatanDao.save(indikatorJabatan);

		addLoggingUser(vo.getLoginUserId(), resultModel.getNoRec(), "Buat data");

		IndikatorKinerjaJabatanVO resultVO = new IndikatorKinerjaJabatanVO();
		resultVO = indikatorJabatanConverter.transferModelToVO(resultModel, resultVO);

		return resultVO;
	}

	public List<String> addAll(List<IndikatorKinerjaJabatanVO> listVO, Integer idLoginUser)
			throws JpaSystemException, ServiceVOException {
		List<String> resultListVO = new ArrayList<>();
		List<IndikatorKinerjaJabatan> listIndikatorJabatan = new ArrayList<>();
		List<Map<String, Object>> listLog = new ArrayList<>();
		Date now = new Date();

		for (IndikatorKinerjaJabatanVO vo : listVO) {
			Jabatan jabatan = jabatanConverter.transferVOToModel(vo.getJabatan(), new Jabatan());
			IndikatorKinerja indikator = indikatorConverter.transferVOToModel(vo.getIndikatorKinerja(),
					new IndikatorKinerja());
			IndikatorKinerjaJabatan indikatorJabatan = indikatorJabatanConverter.transferVOToModel(vo,
					new IndikatorKinerjaJabatan());

			indikatorJabatan.setJabatan(jabatan);
			indikatorJabatan.setIndikatorKinerja(indikator);
			indikatorJabatan.setTanggalPembaharuanData(now);
			listIndikatorJabatan.add(indikatorJabatan);
		}

		Iterable<IndikatorKinerjaJabatan> listResultModel = indikatorKinerjaJabatanDao.save(listIndikatorJabatan);
		for (IndikatorKinerjaJabatan resultModel : listResultModel) {
			Map<String, Object> mapLog = new HashMap<>();
			mapLog.put("idLoginUser", idLoginUser);
			mapLog.put("idReferensi", resultModel.getNoRec());
			mapLog.put("keterangan", "Buat data");
			listLog.add(mapLog);

			IndikatorKinerjaJabatanVO resultVO = new IndikatorKinerjaJabatanVO();
			resultVO = indikatorJabatanConverter.transferModelToVO(resultModel, resultVO);

			resultListVO.add(resultVO.getNoRec());
		}

		addAllLoggingUser(listLog);

		return resultListVO;
	}

	@Override
	public List<String> addAndUpdate(List<IndikatorKinerjaJabatanVO> listVO, Integer idLoginUser)
			throws JpaSystemException, ServiceVOException {
		List<String> resultListVO = new ArrayList<>();
		List<Integer> listIdIndikator = new ArrayList<>();
		List<Integer> listIdJabatan = new ArrayList<>();
		List<IndikatorKinerjaJabatanVO> listAdd = new ArrayList<>();
		List<IndikatorKinerjaJabatanVO> listUpdate = new ArrayList<>();

		for (IndikatorKinerjaJabatanVO vo : listVO) {
			if (CommonUtil.isNullOrEmpty(vo.getNoRec())) {
				listAdd.add(vo);
			} else {
				if (!listIdIndikator.contains(vo.getIndikatorKinerja().getId())) {
					listIdIndikator.add(vo.getIndikatorKinerja().getId());
				}
				if (!listIdJabatan.contains(vo.getJabatan().getId())) {
					listIdJabatan.add(vo.getJabatan().getId());
				}
			}
		}

		if (CommonUtil.isNotNullOrEmpty(listIdIndikator) && CommonUtil.isNotNullOrEmpty(listIdJabatan)) {
			List<Map<String, Object>> allMap = indikatorKinerjaJabatanDao.findAllByIndikator(listIdIndikator,
					listIdJabatan);
			for (Map<String, Object> map : allMap) {
				IndikatorKinerjaJabatanVO vo = new IndikatorKinerjaJabatanVO();
				IndikatorKinerjaVO indikator = new IndikatorKinerjaVO();
				JabatanVO jabatan = new JabatanVO();

				vo.setNoRec(map.get("noRec").toString());
				vo.setKdProfile((short) 0);
				vo.setStatusEnabled(false);
				vo.setTanggalMulaiBerlaku((Date) map.get("tglBerlaku"));
				indikator.setId(Integer.valueOf(map.get("indikatorId").toString()));
				vo.setIndikatorKinerja(indikator);
				jabatan.setId(Integer.valueOf(map.get("jabatanId").toString()));
				vo.setJabatan(jabatan);

				listUpdate.add(vo);
			}
		}

		if (CommonUtil.isNotNullOrEmpty(listAdd)) {
			resultListVO = addAll(listAdd, idLoginUser);
		}
		if (CommonUtil.isNotNullOrEmpty(listUpdate) && CommonUtil.isNotNullOrEmpty(resultListVO)) {
			resultListVO.addAll(updateAll(listUpdate, idLoginUser));
		} else if (CommonUtil.isNotNullOrEmpty(listUpdate) && CommonUtil.isNullOrEmpty(resultListVO)) {
			resultListVO = updateAll(listUpdate, idLoginUser);
		}

		return resultListVO;
	}

	@Override
	public IndikatorKinerjaJabatanVO update(IndikatorKinerjaJabatanVO vo)
			throws JpaSystemException, ServiceVOException {
		IndikatorKinerjaJabatan indikatorJabatanLama = indikatorKinerjaJabatanDao.findOne(vo.getNoRec());
		IndikatorKinerjaJabatan indikatorJabatanBaru = indikatorJabatanConverter.transferVOToModel(vo,
				indikatorJabatanLama);

		List<Map<String, Object>> existedOthersMapping = findUsedKontrakByMapping(
				indikatorJabatanBaru.getIndikatorKinerjaId(), indikatorJabatanBaru.getJabatanId());

		if (CommonUtil.isNotNullOrEmpty(vo.getJabatan())) {
			Jabatan jabatan = jabatanConverter.transferVOToModel(vo.getJabatan(), new Jabatan());
			indikatorJabatanBaru.setJabatan(jabatan);
		}

		if (CommonUtil.isNotNullOrEmpty(vo.getIndikatorKinerja())) {
			IndikatorKinerja indikator = indikatorConverter.transferVOToModel(vo.getIndikatorKinerja(),
					new IndikatorKinerja());
			indikatorJabatanBaru.setIndikatorKinerja(indikator);
		}

		IndikatorKinerjaJabatanVO resultVO = new IndikatorKinerjaJabatanVO();
		if (existedOthersMapping.size() > 0 && !indikatorJabatanBaru.getStatusEnabled()) {
			resultVO.setResponseMessage("Indikator sudah dipakai di kontrak kerja, tidak dapat dihapus!");
		} else {
			indikatorJabatanBaru.setTanggalPembaharuanData(new Date());
			IndikatorKinerjaJabatan resultModel = indikatorKinerjaJabatanDao.save(indikatorJabatanBaru);

			addLoggingUser(vo.getLoginUserId(), resultModel.getNoRec(), "Edit data");

			resultVO = indikatorJabatanConverter.transferModelToVO(resultModel, resultVO);
		}

		return resultVO;
	}

	/**
	 * 
	 * @param listVO
	 *            : mapping indikator yang akan dihapus
	 * @param idLoginUser
	 *            : identitas user saat login
	 * @return Daftar identitas transaksi mapping indikator
	 * @throws JpaSystemException
	 * @throws ServiceVOException
	 */
	public List<String> updateAll(List<IndikatorKinerjaJabatanVO> listVO, Integer idLoginUser)
			throws JpaSystemException, ServiceVOException {
		List<String> resultListVO = new ArrayList<>();
		List<IndikatorKinerjaJabatan> listIndikatorJabatanBaru = new ArrayList<>();
		List<Map<String, Object>> listLog = new ArrayList<>();
		Date now = new Date();

		for (IndikatorKinerjaJabatanVO vo : listVO) {
			IndikatorKinerjaJabatan indikatorJabatanLama = indikatorKinerjaJabatanDao.findOne(vo.getNoRec());

			Jabatan jabatan = jabatanConverter.transferVOToModel(vo.getJabatan(), new Jabatan());
			IndikatorKinerja indikator = indikatorConverter.transferVOToModel(vo.getIndikatorKinerja(),
					new IndikatorKinerja());
			IndikatorKinerjaJabatan indikatorJabatanBaru = indikatorJabatanConverter.transferVOToModel(vo,
					indikatorJabatanLama);

			List<Map<String, Object>> existedOthersMapping = findUsedKontrakByMapping(
					indikatorJabatanBaru.getIndikatorKinerjaId(), indikatorJabatanBaru.getJabatanId());
			if (existedOthersMapping.size() > 0 && !indikatorJabatanBaru.getStatusEnabled()) {
				resultListVO.add("Indikator sudah dipakai di kontrak kerja, tidak dapat dihapus!");
			} else {
				indikatorJabatanBaru.setJabatan(jabatan);
				indikatorJabatanBaru.setIndikatorKinerja(indikator);
				indikatorJabatanBaru.setTanggalPembaharuanData(now);
				listIndikatorJabatanBaru.add(indikatorJabatanBaru);
			}
		}

		if (CommonUtil.isNotNullOrEmpty(listIndikatorJabatanBaru)) {
			Iterable<IndikatorKinerjaJabatan> listResultModel = indikatorKinerjaJabatanDao
					.save(listIndikatorJabatanBaru);
			for (IndikatorKinerjaJabatan resultModel : listResultModel) {
				Map<String, Object> mapLog = new HashMap<>();
				mapLog.put("idLoginUser", idLoginUser);
				mapLog.put("idReferensi", resultModel.getNoRec());
				mapLog.put("keterangan", "Edit data");
				listLog.add(mapLog);

				IndikatorKinerjaJabatanVO resultVO = new IndikatorKinerjaJabatanVO();
				resultVO = indikatorJabatanConverter.transferModelToVO(resultModel, resultVO);

				resultListVO.add(resultVO.getNoRec());
			}

			addAllLoggingUser(listLog);
		}

		return resultListVO;
	}

	@Override
	public Boolean delete(String key) throws JpaSystemException {
		indikatorKinerjaJabatanDao.delete(key);

		return true;
	}

	@Override
	public IndikatorKinerjaJabatanVO findById(String key) throws JpaSystemException {
		IndikatorKinerjaJabatanVO result = new IndikatorKinerjaJabatanVO();

		IndikatorKinerjaJabatan indikatorJabatan = indikatorKinerjaJabatanDao.findOne(key);
		if (CommonUtil.isNotNullOrEmpty(indikatorJabatan)) {
			result = indikatorJabatanConverter.transferModelToVO(indikatorJabatan, result);
		}

		return result;
	}

	@Override
	public List<IndikatorKinerjaJabatanVO> findAll() throws JpaSystemException {
		List<IndikatorKinerjaJabatanVO> result = new ArrayList<IndikatorKinerjaJabatanVO>();

		Iterable<IndikatorKinerjaJabatan> models = indikatorKinerjaJabatanDao.findAll();
		if (CommonUtil.isNotNullOrEmpty(models)) {
			for (IndikatorKinerjaJabatan model : models) {
				IndikatorKinerjaJabatanVO vo = new IndikatorKinerjaJabatanVO();
				vo = indikatorJabatanConverter.transferModelToVO(model, vo);
				result.add(vo);
			}
		}

		return result;
	}

	@Override
	public Map<String, Object> findAllWithPageAndLimitAndSortByAndDirectionParameter(Integer page, Integer limit,
			String sort, String dir) {

		return null;
	}

	@Override
	public Map<String, Object> findAllByJabatan(Integer idJabatan) throws JpaSystemException {
		Map<String, Object> result = new HashMap<String, Object>();

		List<Map<String, Object>> data = indikatorKinerjaJabatanDao.findAllByJabatan(idJabatan);
		for (Integer idJenisIndikator : Arrays.asList(Master.Remunerasi.JENIS_INDIKATOR)) {
			List<Map<String, Object>> dataByJenisIndikator = new ArrayList<>();
			List<Integer> listIdIndikator = new ArrayList<>();
			for (Map<String, Object> map : data) {
				if (map.get("jenisIndikator").equals(idJenisIndikator)
						&& !listIdIndikator.contains(map.get("indikatorId"))) {
					listIdIndikator.add(Integer.valueOf(map.get("indikatorId").toString()));
					dataByJenisIndikator.add(map);
				}
			}

			if (idJenisIndikator.equals(1)) {
				result.put("Kuantitas", dataByJenisIndikator);
			} else if (idJenisIndikator.equals(2)) {
				result.put("Kualitas", dataByJenisIndikator);
			} else if (idJenisIndikator.equals(3)) {
				result.put("Perilaku", dataByJenisIndikator);
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> findAllByIndikator(Integer idIndikator) throws JpaSystemException {
		List<Map<String, Object>> data = new ArrayList<>();
		List<Integer> listIdJabatan = new ArrayList<>();

		List<Map<String, Object>> result = indikatorKinerjaJabatanDao.findAllJabatan();
		List<Map<String, Object>> allMap = indikatorKinerjaJabatanDao.findAllByIndikator(idIndikator);
		for (Map<String, Object> map : allMap) {
			if (!listIdJabatan.contains(map.get("jabatanId"))) {
				listIdJabatan.add(Integer.valueOf(map.get("jabatanId").toString()));
				data.add(map);
			}
		}

		for (Map<String, Object> mapRs : result) {
			for (Map<String, Object> map : data) {
				if (mapRs.get("jabatanId").equals(map.get("jabatanId"))) {
					mapRs.put("statusPilih", true);
					mapRs.put("noRec", map.get("noRec"));
					mapRs.put("tglBerlaku", map.get("tglBerlaku"));
					mapRs.put("tglPembaharuanData", map.get("tglPembaharuanData"));
					break;
				}
			}
			if (CommonUtil.isNullOrEmpty(mapRs.get("noRec"))) {
				mapRs.put("statusPilih", false);
				mapRs.put("noRec", null);
				mapRs.put("tglBerlaku", null);
				mapRs.put("tglPembaharuanData", null);
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> findDupMap(Integer idIndikator, Integer idJabatan, Long tglBerlaku)
			throws JpaSystemException {
		List<Map<String, Object>> result = indikatorKinerjaJabatanDao.findDupMap(idIndikator, idJabatan,
				new Date(tglBerlaku));

		return result;
	}

	@Override
	public List<Map<String, Object>> findIndikatorByUnit(Integer jenisIndikator, Integer idUnitKerja,
			Integer levelJabatan) throws JpaSystemException {
		List<Map<String, Object>> result = new ArrayList<>();
		List<Integer> listIdIndikator = new ArrayList<>();

		List<Map<String, Object>> data = indikatorKinerjaJabatanDao.findIndikatorByUnit(jenisIndikator, idUnitKerja);

		if (levelJabatan > 1) {
			for (Map<String, Object> map : data) {
				if (map.get("levelJabatan").equals(levelJabatan) || map.get("levelJabatan").equals(levelJabatan - 1)) {
					if (!listIdIndikator.contains(map.get("id"))) {
						listIdIndikator.add(Integer.valueOf(map.get("id").toString()));
						map.remove("levelJabatan");
						result.add(map);
					}
				}
			}
		} else {
			for (Map<String, Object> map : data) {
				if (map.get("levelJabatan").equals(levelJabatan)) {
					if (!listIdIndikator.contains(map.get("id"))) {
						listIdIndikator.add(Integer.valueOf(map.get("id").toString()));
						map.remove("levelJabatan");
						result.add(map);
					}
				}
			}
		}

		return result;
	}

	public List<Map<String, Object>> findUsedKontrakByMapping(Integer idIndikator, Integer idJabatan)
			throws JpaSystemException {
		List<Map<String, Object>> result = logbookKinerjaDao.findUsedKontrakByMapping(idIndikator, idJabatan);

		return result;
	}

}
