package com.jasamedika.medifirst2000.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
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 org.springframework.transaction.annotation.Transactional;

import com.jasamedika.medifirst2000.constants.Master;
import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.AntrianPasienDiPeriksaDao;
import com.jasamedika.medifirst2000.dao.JadwalDokterDao;
import com.jasamedika.medifirst2000.dao.KonsultasiDao;
import com.jasamedika.medifirst2000.dao.PasienDaftarDao;
import com.jasamedika.medifirst2000.dao.PasienDiRujukKeIntExtDao;
import com.jasamedika.medifirst2000.dao.RuanganDao;
import com.jasamedika.medifirst2000.dao.RunningNumberDao;
import com.jasamedika.medifirst2000.dao.StrukOrderDao;
import com.jasamedika.medifirst2000.dto.RuanganJumlah;
import com.jasamedika.medifirst2000.entities.AntrianPasienDiPeriksa;
import com.jasamedika.medifirst2000.entities.JadwalDokter;
import com.jasamedika.medifirst2000.entities.Konsultasi;
import com.jasamedika.medifirst2000.entities.PasienDaftar;
import com.jasamedika.medifirst2000.entities.PasienDiRujukKeIntExt;
import com.jasamedika.medifirst2000.entities.Pegawai;
import com.jasamedika.medifirst2000.entities.Ruangan;
import com.jasamedika.medifirst2000.entities.RunningNumber;
import com.jasamedika.medifirst2000.entities.StrukOrder;
import com.jasamedika.medifirst2000.enums.StatusAntrianEnum;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.AntrianPasienDiPeriksaService;
import com.jasamedika.medifirst2000.service.KonsultasiService;
import com.jasamedika.medifirst2000.service.LoginUserService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.util.DateUtil;
import com.jasamedika.medifirst2000.util.JsonUtil;
import com.jasamedika.medifirst2000.util.StringUtil;
import com.jasamedika.medifirst2000.vo.KonsultasiVO;
import com.jasamedika.medifirst2000.vo.PegawaiVO;
import com.jasamedika.medifirst2000.vo.RuanganVO;

/**
 * Implement class for PAPSkriningGiziService
 * 
 * @author Askur
 */
@Service("KonsultasiService")
public class KonsultasiServiceImpl extends BaseVoServiceImpl implements KonsultasiService<KonsultasiVO> {
	@Autowired
	private KonsultasiDao konsultasiDao;

	@Autowired
	private BaseConverterImpl<KonsultasiVO, Konsultasi> konsultasiConverter;

	@Autowired
	private BaseConverterImpl<RuanganVO, Ruangan> ruanganConverter;

	@Autowired
	private BaseConverterImpl<PegawaiVO, Pegawai> pegawaiConverter;

	@Autowired
	private AntrianPasienDiPeriksaDao antrianPasienDiPeriksaDao;

	@Autowired
	private PasienDaftarDao pasienDaftarDao;

	@Autowired
	private PasienDiRujukKeIntExtDao pasienDiRujukKeIntExtDao;

	@Autowired
	private RunningNumberDao runningNumberDao;

	@Autowired
	private LoginUserService loginUserService;

	@Autowired
	private StrukOrderDao strukOrderDao;

	@Autowired
	private RuanganDao ruanganDao;

	@Autowired
	private AntrianPasienDiPeriksaService antrianPasienDiPeriksaService;

	@Autowired
	private JadwalDokterDao jadwalDokterDao;

	@Override
	public Map<String, Object> addKonsultasi(KonsultasiVO vo) {
		Map<String, Object> result = new HashMap<String, Object>();
		Konsultasi konsultasi = konsultasiConverter.transferVOToModel(vo, new Konsultasi());
		AntrianPasienDiPeriksa antrian = antrianPasienDiPeriksaDao
				.findByNoRec(vo.getAntrianPasienDiPeriksa().getNoRec());
		konsultasi.setAntrianPasienDiPeriksa(antrian);
		if (CommonUtil.isNotNullOrEmpty(vo.getTujuanKonsultasi())) {
			Ruangan ruangan = ruanganConverter.transferVOToModel(vo.getTujuanKonsultasi(), new Ruangan());
			konsultasi.setTujuanKonsultasi(ruangan);
		}
		Konsultasi resultModel = konsultasiDao.save(konsultasi);
		try {
			result.put("konsultasi", JsonUtil.ToMapObject(resultModel));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return result;
	}

	@Override
	@Transactional(readOnly = false)
	public Map<String, Object> addKonsultasi2(KonsultasiVO vo) {
		Map<String, Object> result = new HashMap<String, Object>();
		if (CommonUtil.isNotNullOrEmpty(vo.getNoRec())) {
			PasienDiRujukKeIntExt pasienDiRujukKeIntExt = pasienDiRujukKeIntExtDao.findOne(vo.getNoRec());
			pasienDiRujukKeIntExt.setJawabanKonsultasi(vo.getJawabanKonsultasi());
			PasienDiRujukKeIntExt resultModel = pasienDiRujukKeIntExtDao.save(pasienDiRujukKeIntExt);
			result.put("noRec", resultModel.getNoRec());
		} else {
			Konsultasi konsultasi = konsultasiConverter.transferVOToModel(vo, new Konsultasi());
			PasienDiRujukKeIntExt pasienDiRujukKeIntExt = new PasienDiRujukKeIntExt();
			AntrianPasienDiPeriksa antrian = antrianPasienDiPeriksaDao
					.findByNoRec(vo.getAntrianPasienDiPeriksa().getNoRec());
			PasienDaftar pasienDaftar = antrian.getPasienDaftar();
			Ruangan ruanganTujuan = null;
			Integer hitungBilik = ruanganDao.countRuanganBilik(vo.getTujuanKonsultasi().getId());
			// System.out.println("QQQQQQQQQQQQQQQQ : "+"
			// "+vo.getTujuanKonsultasi().getId()+"
			// "+vo.getTanggalKonsultasi());
			if (hitungBilik == 0) {
				ruanganTujuan = ruanganConverter.transferVOToModel(vo.getTujuanKonsultasi(), new Ruangan());
			} else {
				Ruangan r = findRuanganBilik(vo.getTujuanKonsultasi().getId(), vo.getTanggalKonsultasi());
				ruanganTujuan = r;
			}

			// Ruangan
			// ruanganTujuan=ruanganConverter.transferVOToModel(vo.getTujuanKonsultasi(),
			// new Ruangan());
			Ruangan ruanganAsal = antrian.getRuangan();

			// save konsultasi ke antrian pasien di periksa
			AntrianPasienDiPeriksa antrianPasienDiPeriksa = new AntrianPasienDiPeriksa();
			antrianPasienDiPeriksa.setRuangan(ruanganTujuan);
			StrukOrder strukOrder = new StrukOrder();
			strukOrder.setNoOrder(getRunningNumber("NoOrder"));
			strukOrder.setTglOrder(new Date());
			strukOrder.setIsDelivered((byte) 1);
			strukOrder.setQtyJenisProduk(1.0);
			strukOrder.setNoCm(pasienDaftar.getPasien());
			strukOrder.setNoRegistrasi(pasienDaftar);
			strukOrder.setQtyProduk(1.0);
			strukOrder.setTotalBeaMaterai(0.0);
			strukOrder.setTotalBiayaKirim(0.0);
			strukOrder.setTotalBiayaTambahan(0.0);
			strukOrder.setTotalHargaSatuan(0.0);
			strukOrder.setTotalDiscount(0.0);
			strukOrder.setTotalHarusDibayar(0.0);
			strukOrder.setTotalPph(0.0);
			strukOrder.setTotalPpn(0.0);
			strukOrder.setRuanganTujuan(ruanganTujuan);
			strukOrder.setRuangan(ruanganAsal);
			strukOrder.setKeteranganOrder("Konsultasi");
			strukOrder.setPegawaiOrder(loginUserService.getLoginUser().getPegawai());
			StrukOrder strukOrderSave = strukOrderDao.save(strukOrder);
			antrianPasienDiPeriksa.setStrukOrder(strukOrderSave);
			antrianPasienDiPeriksa.setTglRegistrasi(strukOrderSave.getTglOrder());
			antrianPasienDiPeriksa.setStatusPasien((byte) 1);

			PegawaiVO pegawaiVo = new PegawaiVO();

			// pilih dokter yang otomatis dan per quota
			List<JadwalDokter> jadwalDokters = jadwalDokterDao.findJadwalByTanggalRuangan(ruanganTujuan.getId(),
					vo.getTanggalKonsultasi());
			Integer maxQuota = 0;
			for (JadwalDokter jadwalDokter : jadwalDokters) {
				if (jadwalDokter.getQuota() != null && jadwalDokter.getQuota() > maxQuota) {
					maxQuota = jadwalDokter.getQuota();
				}
			}
			Boolean valid = false;
			for (JadwalDokter jadwalDokter : jadwalDokters) {
				if (jadwalDokter.getQuota() != null && jadwalDokter.getQuota() < maxQuota) {
					valid = true;
					jadwalDokter.setQuota(jadwalDokter.getQuota() + 1);
					jadwalDokterDao.save(jadwalDokter);
					pegawaiVo.setId(jadwalDokter.getDokter().getId());
					antrianPasienDiPeriksa.setPegawai(pegawaiConverter.transferVOToModel(pegawaiVo, new Pegawai()));
					break;
				}
			}
			if (!valid) {
				for (JadwalDokter jadwalDokter : jadwalDokters) {
					if (jadwalDokter.getQuota() == null || jadwalDokter.getQuota() == maxQuota) {
						valid = true;
						if (jadwalDokter.getQuota() == null)
							jadwalDokter.setQuota(0);
						jadwalDokter.setQuota(jadwalDokter.getQuota() + 1);
						jadwalDokterDao.save(jadwalDokter);
						pegawaiVo.setId(jadwalDokter.getDokter().getId());
						antrianPasienDiPeriksa.setPegawai(pegawaiConverter.transferVOToModel(pegawaiVo, new Pegawai()));
						break;
					}
				}
			} // added by susy 2017-09-18
			if (CommonUtil.isNotNullOrEmpty(pasienDaftar)) {
				pasienDaftar.setRuangan(ruanganTujuan);
				antrianPasienDiPeriksa.setPasienDaftar(pasienDaftar);
				PasienDaftar model = pasienDaftarDao.save(pasienDaftar);
				result.put("noRecasienDaftar", model.getNoRec());
				List<Integer> antrianPasienDiperiksaId = antrianPasienDiPeriksaDao
						.findByNoRecPasienDaftarAndRuanganAsal(model.getNoRec());
				if (CommonUtil.isNotNullOrEmpty(antrianPasienDiperiksaId)) {
					Ruangan r = ruanganDao.findById(antrianPasienDiperiksaId.get(0));
					if (CommonUtil.isNotNullOrEmpty(r)) {
						antrianPasienDiPeriksa.setRuanganAsal(r);
						String noRecAntrianBefore = updateTglPulang(model.getNoRec(), r.getId());
						result.put("noRecAntrianBefore", noRecAntrianBefore);
					}
				}
			}

			antrianPasienDiPeriksa.setAsalRujukan(antrian.getAsalRujukan());
			antrianPasienDiPeriksa.setKelas(antrian.getKelas());
			antrianPasienDiPeriksa.setTglMasuk(new Date());
			antrianPasienDiPeriksa.setNoAntrian(antrianPasienDiPeriksaService
					.getFormatNumberByMonthYearRuangan(vo.getTanggalKonsultasi(), vo.getTujuanKonsultasi().getId()));
			antrianPasienDiPeriksa.setStatusAntrian(StatusAntrianEnum.DIPANGGIL_DOKTER.getVal());
			AntrianPasienDiPeriksa antrianPasienDiPeriksaSave = antrianPasienDiPeriksaDao.save(antrianPasienDiPeriksa);
			result.put("noRecAntrianPasienDiPeriksa", antrianPasienDiPeriksaSave.getNoRec());

			pasienDiRujukKeIntExt.setRuanganTujuan(ruanganTujuan);
			pasienDiRujukKeIntExt.setNoAntrianTujuan(pasienDiRujukKeIntExtDao
					.getCountByMonthAndYearBilik(konsultasi.getTanggalKonsultasi(), ruanganTujuan.getId()) + 1);
			pasienDiRujukKeIntExt.setNoCm(antrianPasienDiPeriksaSave.getPasienDaftar().getPasien());
			pasienDiRujukKeIntExt.setNoRegistrasi(antrianPasienDiPeriksaSave);
			pasienDiRujukKeIntExt.setRuanganPerujuk(antrianPasienDiPeriksaSave.getRuangan());
			pasienDiRujukKeIntExt.setDokterPerujuk(loginUserService.getLoginUser().getPegawai());
			pasienDiRujukKeIntExt.setStatusPasienTujuan((byte) 1);
			pasienDiRujukKeIntExt.setKeteranganLainnya(konsultasi.getIkhtiarKlinik());
			pasienDiRujukKeIntExt.setTglDirujuk(konsultasi.getTanggalKonsultasi());
			PasienDiRujukKeIntExt resultModel = pasienDiRujukKeIntExtDao.save(pasienDiRujukKeIntExt);
			try {
				result.put("konsultasi", JsonUtil.ToMapObject(resultModel));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	@Override
	public KonsultasiVO add(KonsultasiVO vo) throws JpaSystemException, ServiceVOException {
		return null;
	}

	@Override
	public KonsultasiVO update(KonsultasiVO vo) throws JpaSystemException, ServiceVOException {
		return null;
	}

	@Override
	public Boolean delete(String key) throws JpaSystemException {
		return null;
	}

	@Override
	public KonsultasiVO findById(String key) throws JpaSystemException {
		return null;
	}

	@Override
	public List<KonsultasiVO> findAll() throws JpaSystemException {
		return null;
	}

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

	@Transactional(readOnly = false)
	private String getRunningNumber(String kegunaan) {
		RunningNumber runningNumber = runningNumberDao.findByResetAndKegunaan("0", kegunaan);

		Integer number = (runningNumber.getNomerTerbaru() + (Integer) 1);
		runningNumber.setNomerTerbaru(runningNumber.getNomerTerbaru() + (Integer) 1);
		String noOrderIntern = StringUtil.formatNumber(number.toString(), 6);
		runningNumberDao.save(runningNumber);
		return noOrderIntern;
	}

	private Ruangan findRuanganBilik(Integer id, Date tglRegistrasi) {
		List<RuanganJumlah> output = new ArrayList<RuanganJumlah>();
		// List<Ruangan> listRuangan=ruanganDao.findRuanganByParent(id);
		List<Ruangan> listRuangan = new ArrayList<Ruangan>();
		List<JadwalDokter> listJadwal = jadwalDokterDao.findJadwalByTanggalRuanganBilik2(id, tglRegistrasi);
		for (JadwalDokter jd : listJadwal) {
			listRuangan.add(jd.getRuangan());
		}
		for (Ruangan localR : listRuangan) {
			RuanganJumlah jml = new RuanganJumlah();
			// System.out.println("RUANGAN BILIK A : "+localR.getId()+"
			// "+localR.getNamaRuangan());
			List<Object[]> list = antrianPasienDiPeriksaDao.findRuanganByRuanganId(localR.getId(),
					DateUtil.formatDate(tglRegistrasi));
			for (Object[] o : list) {
				Long count = (Long) o[0];
				String namaR = (String) o[1];
				String tgl = (String) o[2];
				Integer idR = (Integer) o[3];
				if (localR.getNamaRuangan().equals(namaR)) {
					jml.setCount(count);
					jml.setNamaRuangan(namaR);
					jml.setIdRuangan(idR);
					jml.setTglRegistrasi(tgl);
					output.add(jml);
				}
			}
			if (jml.getIdRuangan() == null) {
				jml.setCount(0L);
				jml.setNamaRuangan(localR.getNamaRuangan());
				jml.setIdRuangan(localR.getId());
				output.add(jml);
			}
		}
		Collections.sort(output, new Comparator<RuanganJumlah>() {
			@Override
			public int compare(RuanganJumlah t, RuanganJumlah t1) {
				int a = Integer.parseInt(String.valueOf(t.getCount() - t1.getCount()));
				if (a == 0L) {
					int a1 = t.getNamaRuangan().compareTo(t1.getNamaRuangan());
					return a1;
				} else
					return a;
			}
		});
		// for(RuanganJumlah l:output){
		// System.out.println("RUANGAN BILIK B : "+l.getCount()+"
		// "+l.getIdRuangan()+" "+l.getNamaRuangan()+" "+l.getTglRegistrasi());
		// }
		Ruangan ruang = new Ruangan();
		ruang.setId(output.get(0).getIdRuangan());
		return ruang;
	}

	@Override
	public List<Map<String, Object>> getRiwayatKonsultasi(String noCm, String startDate, String endDate) {
		List<Map<String, Object>> data = konsultasiDao.findRiwayatKonsultasi(noCm, startDate, endDate);
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		for (Map<String, Object> temp : data) {
			String status = (String) temp.get("statusAntrian");
			Integer indeks = Integer.valueOf(status);
			String statusAntrian = StatusAntrianEnum.values()[indeks].toString();
			temp.put("status", statusAntrian);

			Map<String, Object> cek = konsultasiDao.getIkhtiarKlinik((String) temp.get("noRecAntrian"));
			temp.put("noRecJawaban", cek.get("noRecJawaban"));
			temp.put("keteranganKonsultasi", cek.get("keteranganKonsultasi"));
			temp.put("jawabanKonsultasi", cek.get("jawabanKonsultasi"));
			result.add(temp);
		}
		return result;
	}

	@Override
	public String updateTglPulang(String noRec, Integer idRuangan) {
		String result = "-";
		List<AntrianPasienDiPeriksa> listAntrian = antrianPasienDiPeriksaDao.findAntrianBefore(noRec, idRuangan);
		if (CommonUtil.isNotNullOrEmpty(listAntrian)) {
			AntrianPasienDiPeriksa data = listAntrian.get(0);
			data.setTglKeluar(new Date());
			AntrianPasienDiPeriksa model = antrianPasienDiPeriksaDao.save(data);
			result = model.getNoRec();
		}
		return result;
	}

	@Override
	public List<Map<String, Object>> findAllKonsultasiTindakanKosong(String strTglAwal, String strTglAkhir)
			throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");

		Date tglAwal = sdf.parse(strTglAwal);
		Date tglAkhir = sdf.parse(strTglAkhir);

		List<Integer> inapDanLab = new ArrayList<>();
		inapDanLab.add(Master.Departemen.RAWAT_INAP);
		inapDanLab.add(Master.Departemen.LABORATORIUM);

		List<Integer> excJenisProduk = new ArrayList<>();
		excJenisProduk.addAll(Arrays.asList(Master.JenisProduk.NONTINDAKAN));
		excJenisProduk.addAll(Arrays.asList(Master.JenisProduk.NONKONSULTASI));
		excJenisProduk.add(Master.JenisProduk.LAB_KLINIK);

		List<Integer> idsRegDJPPenunjangLab = splitDataSettingDatafixed("penunjang_laboratorium");

		List<Map<String, Object>> result = konsultasiDao.findAllKonsultasiTindakanKosong(tglAwal, tglAkhir, inapDanLab,
				Arrays.asList(Master.Pegawai.ADMINISTRATOR), Master.Produk.KARCIS, excJenisProduk, idsRegDJPPenunjangLab);

		return result;
	}
}
