package com.jasamedika.medifirst2000.service.impl;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
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.HargaNettoProdukByKelasDao;
import com.jasamedika.medifirst2000.dao.LoggingUserDao;
import com.jasamedika.medifirst2000.dao.MapPegawaiJabatanToUnitKerjaDao;
import com.jasamedika.medifirst2000.dao.MapProdukKelompokKerjaDao;
import com.jasamedika.medifirst2000.dao.MapRuanganToProdukDao;
import com.jasamedika.medifirst2000.dao.PelayananPasienPetugasDao;
import com.jasamedika.medifirst2000.dao.ProdukDao;
import com.jasamedika.medifirst2000.dao.SettingDataFixedDao;
import com.jasamedika.medifirst2000.dao.SkoringTindakanMedisDao;
import com.jasamedika.medifirst2000.dao.SubUnitKerjaDao;
import com.jasamedika.medifirst2000.entities.LoggingUser;
import com.jasamedika.medifirst2000.entities.LoginUser;
import com.jasamedika.medifirst2000.entities.Produk;
import com.jasamedika.medifirst2000.entities.SkoringTindakanMedis;
import com.jasamedika.medifirst2000.entities.SubUnitKerjaPegawai;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.SkoringTindakanMedisService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.vo.ProdukVO;
import com.jasamedika.medifirst2000.vo.SkoringTindakanMedisVO;
import com.jasamedika.medifirst2000.vo.SubUnitKerjaPegawaiVO;

@Service("skoringTindakanMedisService")
public class SkoringTindakanMedisServiceImpl extends BaseVoServiceImpl implements SkoringTindakanMedisService {

	@Autowired
	private BaseConverterImpl<ProdukVO, Produk> produkConverter;

	@Autowired
	private BaseConverterImpl<SubUnitKerjaPegawaiVO, SubUnitKerjaPegawai> subunitKerjaConverter;

	@Autowired
	private BaseConverterImpl<SkoringTindakanMedisVO, SkoringTindakanMedis> skoringTindakanMedisConverter;

	@Autowired
	private SkoringTindakanMedisDao skoringTindakanMedisDao;

	@Autowired
	private ProdukDao produkDao;

	@Autowired
	private SettingDataFixedDao settingDataFixedDao;

	@Autowired
	private LoggingUserDao loggingUserDao;

	@Autowired
	private MapPegawaiJabatanToUnitKerjaDao mappingJabatanDao;

	@Autowired
	private SubUnitKerjaDao subUnitKerjaDao;

	@Autowired
	private HargaNettoProdukByKelasDao hargaNettoProdukByKelasDao;

	@Autowired
	private MapRuanganToProdukDao mapRuanganToProdukDao;

	@Autowired
	private PelayananPasienPetugasDao pelayananPasienPetugasDao;

	@Autowired
	private MapProdukKelompokKerjaDao mapProdukKelompokKerjaDao;

	public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
		Set<Object> seen = ConcurrentHashMap.newKeySet();
		return t -> seen.add(keyExtractor.apply(t));
	}

	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("Skoring Tindakan Medis");
		loggingUser.setReferensiId(idReferensi);
		loggingUser.setReferensi("sdm_skoringtindakanmedis_t");
		loggingUser.setKeterangan(keterangan);

		loggingUserDao.save(loggingUser);
	}

	@Override
	public SkoringTindakanMedisVO add(SkoringTindakanMedisVO vo) throws JpaSystemException, ServiceVOException {
		Produk produk = produkConverter.transferVOToModel(vo.getProduk(), new Produk());
		SubUnitKerjaPegawai kelompokKerja = subunitKerjaConverter.transferVOToModel(vo.getKelompokKerja(),
				new SubUnitKerjaPegawai());
		SkoringTindakanMedis skoringTindakanMedis = skoringTindakanMedisConverter.transferVOToModel(vo,
				new SkoringTindakanMedis());

		skoringTindakanMedis.setProduk(produk);
		skoringTindakanMedis.setKelompokKerja(kelompokKerja);
		skoringTindakanMedis.setTanggalPembaharuanData(new Date());
		SkoringTindakanMedis resultModel = skoringTindakanMedisDao.save(skoringTindakanMedis);

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

		SkoringTindakanMedisVO resultVO = new SkoringTindakanMedisVO();
		resultVO = skoringTindakanMedisConverter.transferModelToVO(resultModel, resultVO);

		return resultVO;
	}

	@Override
	public SkoringTindakanMedisVO update(SkoringTindakanMedisVO vo) throws JpaSystemException, ServiceVOException {
		SkoringTindakanMedis skoringTindakanMedisLama = skoringTindakanMedisDao.findOne(vo.getNoRec());

		Produk produk = produkConverter.transferVOToModel(vo.getProduk(), new Produk());
		SubUnitKerjaPegawai kelompokKerja = subunitKerjaConverter.transferVOToModel(vo.getKelompokKerja(),
				new SubUnitKerjaPegawai());
		SkoringTindakanMedis skoringTindakanMedisBaru = skoringTindakanMedisConverter.transferVOToModel(vo,
				skoringTindakanMedisLama);

		skoringTindakanMedisBaru.setProduk(produk);
		skoringTindakanMedisBaru.setKelompokKerja(kelompokKerja);
		skoringTindakanMedisBaru.setTanggalPembaharuanData(new Date());
		SkoringTindakanMedis resultModel = skoringTindakanMedisDao.save(skoringTindakanMedisBaru);

		if (vo.getStatusEnabled()) {
			addLoggingUser(vo.getLoginUserId(), resultModel.getNoRec(), "Edit data");
		} else if (!vo.getStatusEnabled()) {
			addLoggingUser(vo.getLoginUserId(), resultModel.getNoRec(), "Hapus data");
		}

		SkoringTindakanMedisVO resultVO = new SkoringTindakanMedisVO();
		resultVO = skoringTindakanMedisConverter.transferModelToVO(resultModel, resultVO);

		return resultVO;
	}

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

		return true;
	}

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

		SkoringTindakanMedis skoringTindakanMedis = skoringTindakanMedisDao.findOne(key);
		if (CommonUtil.isNotNullOrEmpty(skoringTindakanMedis)) {
			result = skoringTindakanMedisConverter.transferModelToVO(skoringTindakanMedis, result);
		}

		return result;
	}

	@Override
	public List<SkoringTindakanMedisVO> findAll() throws JpaSystemException {
		List<SkoringTindakanMedisVO> result = new ArrayList<SkoringTindakanMedisVO>();
		Iterable<SkoringTindakanMedis> models = skoringTindakanMedisDao.findAll();
		for (SkoringTindakanMedis model : models) {
			SkoringTindakanMedisVO vo = new SkoringTindakanMedisVO();
			vo = skoringTindakanMedisConverter.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 List<Map<String, Object>> findAllEnabled(List<Integer> listIdKelompokKerja, String namaProduk,
			String detailProduk, Boolean statusVerifikasi) throws JpaSystemException {

		List<Map<String, Object>> result = new ArrayList<>();
		List<Map<String, Object>> data = new ArrayList<>();
		List<Map<String, Object>> filter = new ArrayList<>();

		if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabled();
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnit(listIdKelompokKerja);
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByProduk(namaProduk.toLowerCase());
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByDetail(detailProduk.toLowerCase());
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByVerif(statusVerifikasi);
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitProduk(listIdKelompokKerja, namaProduk.toLowerCase());
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitDetail(listIdKelompokKerja, detailProduk.toLowerCase());
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitVerif(listIdKelompokKerja, statusVerifikasi);
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByProdukDetail(namaProduk.toLowerCase(),
					detailProduk.toLowerCase());
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByProdukVerif(namaProduk.toLowerCase(), statusVerifikasi);
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByDetailVerif(detailProduk.toLowerCase(), statusVerifikasi);
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitProdukDetail(listIdKelompokKerja,
					namaProduk.toLowerCase(), detailProduk.toLowerCase());
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitProdukVerif(listIdKelompokKerja,
					namaProduk.toLowerCase(), statusVerifikasi);
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitDetailVerif(listIdKelompokKerja,
					detailProduk.toLowerCase(), statusVerifikasi);
		} else if (CommonUtil.isNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByProdukDetailVerif(namaProduk.toLowerCase(),
					detailProduk.toLowerCase(), statusVerifikasi);
		} else if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja) && CommonUtil.isNotNullOrEmpty(namaProduk)
				&& CommonUtil.isNotNullOrEmpty(detailProduk) && CommonUtil.isNotNullOrEmpty(statusVerifikasi)) {
			data = skoringTindakanMedisDao.findAllEnabledByUnitProdukDetailVerif(listIdKelompokKerja,
					namaProduk.toLowerCase(), detailProduk.toLowerCase(), statusVerifikasi);
		}

		// filtering
		for (Map<String, Object> mapData : data) {
			boolean isContained = false;
			for (Map<String, Object> mapFilter : filter) {
				if (mapData.get("produkId").equals(mapFilter.get("produkId"))
						&& mapData.get("kelompokKerjaId").equals(mapFilter.get("kelompokKerjaId"))) {
					isContained = true;
					break;
				}
			}
			if (!isContained) {
				Map<String, Object> mapFilter = new HashMap<>();
				mapFilter.put("produkId", mapData.get("produkId"));
				mapFilter.put("kelompokKerjaId", mapData.get("kelompokKerjaId"));
				filter.add(mapFilter);
			}
		}

		for (Map<String, Object> mapFilter : filter) {
			for (Map<String, Object> mapData : data) {
				if (mapFilter.get("produkId").equals(mapData.get("produkId"))
						&& mapFilter.get("kelompokKerjaId").equals(mapData.get("kelompokKerjaId"))) {
					result.add(mapData);
					break;
				}
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> findDaftarInputTindakanByRuanganKelas(Integer idRuangan)
			throws JpaSystemException {
		List<Map<String, Object>> result = produkDao.findDaftarInputTindakanByRuangan(idRuangan);

		return result;
	}

	@Override
	public List<Map<String, Object>> findDuplicateSkoring(String namaProduk, Integer idKelompokKerja, Double skor,
			String detailProduk, Long tglMulaiBerlaku, String noRec) throws JpaSystemException {
		List<Map<String, Object>> result = new ArrayList<>();
		List<String> listNorec = new ArrayList<>();

		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

		String patternText = settingDataFixedDao.getSettingDataFixed("patternTextDuplicate");
		String replacedNamaProduk = namaProduk.replaceAll(patternText, "").toLowerCase();
		String replacedDetailProduk = detailProduk.replaceAll(patternText, "").toLowerCase();
		if (CommonUtil.isNotNullOrEmpty(noRec)) {
			listNorec = skoringTindakanMedisDao.findLastDupSkoring(replacedNamaProduk, idKelompokKerja, skor,
					patternText, replacedDetailProduk, noRec);
			if (CommonUtil.isNullOrEmpty(listNorec)) {
				listNorec = skoringTindakanMedisDao.findDupSkoring(replacedNamaProduk, idKelompokKerja,
						df.format(new Date(tglMulaiBerlaku)), patternText, replacedDetailProduk, noRec);
			}
		} else {
			listNorec = skoringTindakanMedisDao.findLastDupSkoring(replacedNamaProduk, idKelompokKerja, skor,
					patternText, replacedDetailProduk);
			if (CommonUtil.isNullOrEmpty(listNorec)) {
				listNorec = skoringTindakanMedisDao.findDupSkoring(replacedNamaProduk, idKelompokKerja,
						df.format(new Date(tglMulaiBerlaku)), patternText, replacedDetailProduk);
			}
		}

		if (CommonUtil.isNotNullOrEmpty(listNorec)) {
			result = skoringTindakanMedisDao.findAllDup(listNorec);
		}

		return result;
	}

	@Override
	public Map<String, Object> findAkses(Integer idPegawai) throws JpaSystemException {
		Map<String, Object> result = new HashMap<>();
		List<Integer> listRs = new ArrayList<>();
		List<Integer> listIdUnitKerja = new ArrayList<>();
		List<Integer> listUnitKerjaSuperuser = new ArrayList<>();

		listIdUnitKerja.addAll(Arrays.asList(Master.UnitKerja.KSM));
		listUnitKerjaSuperuser.add(Master.UnitKerja.BAG_SDM);

		List<Map<String, Object>> listSuperuser = mappingJabatanDao.findAksesPegawaiPenilai(listIdUnitKerja, idPegawai);
		listSuperuser.addAll(mappingJabatanDao.findAksesPegawaiStaf(listUnitKerjaSuperuser, idPegawai));
		listSuperuser.addAll(mappingJabatanDao.findAksesPegawaiAtasan(listUnitKerjaSuperuser, idPegawai));
		listSuperuser.addAll(mappingJabatanDao.findAksesPegawaiPenilai(listUnitKerjaSuperuser, idPegawai));
		if (CommonUtil.isNotNullOrEmpty(listSuperuser)) {
			listRs.addAll(listIdUnitKerja);

			result.put("isSuperuser", true);
			result.put("isAtasan", false);
			result.put("isStaf", false);
			result.put("listId", listRs);
			result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
		} else {
			List<Map<String, Object>> listAtasan = mappingJabatanDao.findAksesPegawaiAtasan(listIdUnitKerja, idPegawai);
			if (CommonUtil.isNotNullOrEmpty(listAtasan)) {
				for (Map<String, Object> map : listAtasan) {
					if (!listRs.contains(Integer.valueOf(map.get("unitKerjaId").toString()))) {
						listRs.add(Integer.valueOf(map.get("unitKerjaId").toString()));
					}
				}

				result.put("isSuperuser", false);
				result.put("isAtasan", true);
				result.put("isStaf", false);
				result.put("listId", listRs);
				result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
			} else {
				List<Map<String, Object>> listStaf = mappingJabatanDao.findAksesPegawaiStaf(listIdUnitKerja, idPegawai);
				if (CommonUtil.isNotNullOrEmpty(listStaf)) {
					for (Map<String, Object> map : listStaf) {
						if (!listRs.contains(Integer.valueOf(map.get("unitKerjaId").toString()))) {
							listRs.add(Integer.valueOf(map.get("unitKerjaId").toString()));
						}
					}

					result.put("isSuperuser", false);
					result.put("isAtasan", false);
					result.put("isStaf", true);
					result.put("listId", listRs);
					result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
				} else {
					List<Map<String, Object>> listSuperElse = mappingJabatanDao.findAksesPegawaiPenilai(idPegawai);
					if (CommonUtil.isNotNullOrEmpty(listSuperElse)) {
						for (Map<String, Object> map : listSuperElse) {
							if (!listRs.contains(Integer.valueOf(map.get("unitKerjaId").toString()))) {
								listRs.add(Integer.valueOf(map.get("unitKerjaId").toString()));
							}
						}

						result.put("isSuperuser", false);
						result.put("isAtasan", false);
						result.put("isStaf", false);
						result.put("listId", listRs);
						result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
					} else {
						List<Map<String, Object>> listAtasanElse = mappingJabatanDao.findAksesPegawaiAtasan(idPegawai);
						if (CommonUtil.isNotNullOrEmpty(listAtasanElse)) {
							for (Map<String, Object> map : listAtasanElse) {
								if (!listRs.contains(Integer.valueOf(map.get("unitKerjaId").toString()))) {
									listRs.add(Integer.valueOf(map.get("unitKerjaId").toString()));
								}
							}

							result.put("isSuperuser", false);
							result.put("isAtasan", false);
							result.put("isStaf", false);
							result.put("listId", listRs);
							result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
						} else {
							List<Map<String, Object>> listStafElse = mappingJabatanDao.findAksesPegawaiStaf(idPegawai);
							if (CommonUtil.isNotNullOrEmpty(listStafElse)) {
								for (Map<String, Object> map : listStafElse) {
									if (!listRs.contains(Integer.valueOf(map.get("unitKerjaId").toString()))) {
										listRs.add(Integer.valueOf(map.get("unitKerjaId").toString()));
									}
								}

								result.put("isSuperuser", false);
								result.put("isAtasan", false);
								result.put("isStaf", false);
								result.put("listId", listRs);
								result.put("listKk", subUnitKerjaDao.getSubunitKerjaByUnitKerja(listRs));
							}
						}
					}
				}
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> findTindakanBelumAdaSkor(List<Integer> listIdKelompokKerja) {
		List<Map<String, Object>> result = new ArrayList<>();

		List<Map<String, Object>> listProdukMapping = new ArrayList<>();
		List<Map<String, Object>> listProdukScored = new ArrayList<>();
		if (CommonUtil.isNotNullOrEmpty(listIdKelompokKerja)) {
			listProdukMapping = mapProdukKelompokKerjaDao.findAllMapping(listIdKelompokKerja);
			listProdukScored = skoringTindakanMedisDao.findProdukScored(listIdKelompokKerja);
		} else {
			listProdukMapping = mapProdukKelompokKerjaDao.findAllMapping();
			listProdukScored = skoringTindakanMedisDao.findProdukScored();
		}

		List<String> listNorecScored = new ArrayList<>();
		for (Map<String, Object> map : listProdukMapping) {
			for (Map<String, Object> skor : listProdukScored) {
				if (map.get("kelompokKerjaId").equals(skor.get("kelompokKerjaId"))
						&& map.get("produkId").equals(skor.get("produkId"))) {
					listNorecScored.add(map.get("noRec").toString());
				}
			}
		}

		for (Map<String, Object> map : listProdukMapping) {
			if (!listNorecScored.contains(map.get("noRec"))) {
				result.add(map);
			}
		}

		return result;
	}

	@Override
	public Map<String, String> findDeskripsiSkoringTindakanMedis(Integer idProduk, Integer idKelompokKerja) {
		final Map<String, String> result = new ConcurrentHashMap<String, String>();
		final CountDownLatch countDown = new CountDownLatch(4);
		final ExecutorService executor = Executors.newFixedThreadPool(4);

		for (int i = 0; i < 4; i++) {
			final int index = i;
			executor.execute(() -> {
				try {
					if (index == 0) {
						// Deskripsi Diri
						String deskripsiDiri = "";
						Map<String, Object> produk = produkDao.findProdukById(idProduk);
						if (CommonUtil.isNotNullOrEmpty(produk)) {
							deskripsiDiri += produk.get("id").toString() + " - " + produk.get("namaProduk").toString();
						}
						if (CommonUtil.isNotNullOrEmpty(deskripsiDiri)) {
							result.put("produk", deskripsiDiri);
						} else {
							result.put("produk", "-");
						}
					} else if (index == 1) {
						// Deskripsi Tarif
						String deskripsiTarif = "";
						List<Double> listBesarTarif = new ArrayList<>();
						NumberFormat rupiah = NumberFormat.getCurrencyInstance(new Locale("in", "ID"));
						List<Map<String, Object>> daftarTarif = hargaNettoProdukByKelasDao.findTarifTindakan(idProduk,
								Arrays.asList(Master.Kelas.REF_KELAS_KAMAR));
						for (Map<String, Object> tarif : daftarTarif) {
							if (!listBesarTarif.contains(tarif.get("tarif"))) {
								listBesarTarif.add(Double.parseDouble(tarif.get("tarif").toString()));
							}
						}
						if (listBesarTarif.size() == 1) {
							deskripsiTarif += rupiah.format(listBesarTarif.get(0));
						} else {
							for (Map<String, Object> tarif : daftarTarif) {
								if (deskripsiTarif == "") {
									deskripsiTarif += rupiah.format(Double.parseDouble(tarif.get("tarif").toString()))
											+ " (" + tarif.get("kelas").toString() + ")";
								} else {
									deskripsiTarif += ", "
											+ rupiah.format(Double.parseDouble(tarif.get("tarif").toString())) + " ("
											+ tarif.get("kelas").toString() + ")";
								}
							}
						}
						if (CommonUtil.isNotNullOrEmpty(deskripsiTarif)) {
							result.put("tarif", deskripsiTarif);
						} else {
							result.put("tarif", "-");
						}
					} else if (index == 2) {
						// Deskripsi Ruangan Pemeriksaan
						String deskripsiRuanganPemeriksaan = "";
						List<String> daftarRuangan = mapRuanganToProdukDao.findRuanganByTindakan(idProduk);
						for (String ruangan : daftarRuangan) {
							if (deskripsiRuanganPemeriksaan == "") {
								deskripsiRuanganPemeriksaan += ruangan;
							} else {
								deskripsiRuanganPemeriksaan += ", " + ruangan;
							}
						}
						if (CommonUtil.isNotNullOrEmpty(deskripsiRuanganPemeriksaan)) {
							result.put("ruanganPemeriksaan", deskripsiRuanganPemeriksaan);
						} else {
							result.put("ruanganPemeriksaan", "-");
						}
					} else if (index == 3) {
						// Deskripsi Dokter Pelayanan
						String deskripsiDokterPelayanan = "";
						Pageable pageable = new PageRequest(0, 3);
						List<Map<String, Object>> tempList = pelayananPasienPetugasDao.findDokterByTindakan(idProduk,
								idKelompokKerja, pageable);
						List<Map<String, Object>> daftarDokter = tempList.stream()
								.filter(distinctByKey(p -> Integer.parseInt(p.get("id").toString())))
								.collect(Collectors.toList());
						for (Map<String, Object> dokter : daftarDokter) {
							if (deskripsiDokterPelayanan == "") {
								deskripsiDokterPelayanan += dokter.get("namaLengkap").toString();
							} else {
								deskripsiDokterPelayanan += ", " + dokter.get("namaLengkap").toString();
							}
						}
						if (CommonUtil.isNotNullOrEmpty(deskripsiDokterPelayanan)) {
							result.put("dokterPemeriksaTerakhir", deskripsiDokterPelayanan);
						} else {
							result.put("dokterPemeriksaTerakhir", "-");
						}
					}
				} finally {
					countDown.countDown();
				}
			});
		}

		try {
			countDown.await();

			executor.shutdown();
			executor.awaitTermination(5, TimeUnit.MINUTES);

			return result;
		} catch (InterruptedException e) {
			e.printStackTrace();

			executor.shutdownNow();

			return result;
		}
	}

	@Override
	public List<Map<String, Object>> findTindakanLogbookSkor(String namaProduk) {
		List<Map<String, Object>> result = new ArrayList<>();

		List<Integer> idsRegDJPAdminNonPK = splitDataSettingDatafixed("admin_nonpk");
		List<Integer> idsRegDJPMedisUtama = splitDataSettingDatafixed("medis_utama");
		List<Integer> idsRegDJPPenunjangPA = splitDataSettingDatafixed("penunjang_pa");
		List<Integer> idsRegDJPPenunjangPK = splitDataSettingDatafixed("penunjang_pk");
		List<Integer> idsRegDJPPenunjangRad = splitDataSettingDatafixed("penunjang_radiologi");
		List<Integer> idsRegDJPPenunjangLab = splitDataSettingDatafixed("penunjang_laboratorium");

		List<Integer> tempList = new ArrayList<>();
		tempList.addAll(idsRegDJPAdminNonPK);
		tempList.addAll(idsRegDJPMedisUtama);
		tempList.addAll(idsRegDJPPenunjangPA);
		tempList.addAll(idsRegDJPPenunjangPK);
		tempList.addAll(idsRegDJPPenunjangRad);

		List<Integer> listIdDetailJenisProdukLogbookSkor = tempList.stream().sorted().distinct()
				.collect(Collectors.toList());

		Pageable pageable = new PageRequest(0, 50);
		if (CommonUtil.isNotNullOrEmpty(namaProduk)) {
			result = produkDao.findTindakanLogbookSkor(listIdDetailJenisProdukLogbookSkor, namaProduk.toLowerCase(),
					pageable);
		} else {
			result = produkDao.findTindakanLogbookSkor(listIdDetailJenisProdukLogbookSkor, pageable);
		}

		return result;
	}

}
