package com.jasamedika.medifirst2000.service.impl;

import com.jasamedika.medifirst2000.constants.Master;
import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.*;
import com.jasamedika.medifirst2000.dto.RuanganJumlah;
import com.jasamedika.medifirst2000.entities.*;
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;
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 java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 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<>();
		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 | IllegalAccessException e) {
			throw new ServiceVOException(e.getMessage());
		}
		return result;
	}

	@Override
	@Transactional
	public Map<String, Object> addKonsultasi2(KonsultasiVO vo) {
		Map<String, Object> result = new HashMap<>();
		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;
			Integer hitungBilik = ruanganDao.countRuanganBilik(vo.getTujuanKonsultasi().getId());
			if (hitungBilik == 0) {
				ruanganTujuan = ruanganConverter.transferVOToModel(vo.getTujuanKonsultasi(), new Ruangan());
			} else {
				ruanganTujuan = findRuanganBilik(vo.getTujuanKonsultasi().getId(), vo.getTanggalKonsultasi());
			}

			Ruangan ruanganAsal = antrian.getRuangan();

			AntrianPasienDiPeriksa antrianPasienDiPeriksa = new AntrianPasienDiPeriksa();
			antrianPasienDiPeriksa.setRuangan(ruanganTujuan);
			StrukOrder strukOrder = setAndGetStrukOrder(pasienDaftar, ruanganTujuan, ruanganAsal);
			StrukOrder strukOrderSave = strukOrderDao.save(strukOrder);
			antrianPasienDiPeriksa.setStrukOrder(strukOrderSave);
			antrianPasienDiPeriksa.setTglRegistrasi(strukOrderSave.getTglOrder());
			antrianPasienDiPeriksa.setStatusPasien((byte) 1);

			PegawaiVO pegawaiVo = new PegawaiVO();

			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 || Objects.equals(jadwalDokter.getQuota(), maxQuota)) {
						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;
					}
				}
			}
			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 | IllegalAccessException e) {
				throw new ServiceVOException(e.getMessage());
			}
		}
		return result;
	}

	private StrukOrder setAndGetStrukOrder(PasienDaftar pasienDaftar, Ruangan ruanganTujuan, Ruangan ruanganAsal) {
		StrukOrder strukOrder = new StrukOrder();
		strukOrder.setNoOrder(getRunningNumber());
		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());
		return strukOrder;
	}

	@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
	private String getRunningNumber() {
		RunningNumber runningNumber = runningNumberDao.findByResetAndKegunaan("0", "NoOrder");

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

	private Ruangan findRuanganBilik(Integer id, Date tglRegistrasi) {
		List<RuanganJumlah> output = new ArrayList<>();
		List<Ruangan> listRuangan = new ArrayList<>();
		List<JadwalDokter> listJadwal = jadwalDokterDao.findJadwalByTanggalRuanganBilik2(id, tglRegistrasi);
		for (JadwalDokter jd : listJadwal) {
			listRuangan.add(jd.getRuangan());
		}
		for (Ruangan localR : listRuangan) {
			RuanganJumlah jml = new RuanganJumlah();
			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);
			}
		}
		output.sort((t, t1) -> {
			int a = Integer.parseInt(String.valueOf(t.getCount() - t1.getCount()));
			if (a == 0L) {
				return t.getNamaRuangan().compareTo(t1.getNamaRuangan());
			} else
				return a;
		});
		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<>();
		for (Map<String, Object> temp : data) {
			String status = (String) temp.get("statusAntrian");
			int indeks = Integer.parseInt(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<Integer> idsKarcis = getNilaiDataFixByTMT("listKarcisIdProduk", tglAwal);

		return konsultasiDao.findAllKonsultasiTindakanKosong(tglAwal, tglAkhir, inapDanLab,
				Arrays.asList(Master.Pegawai.ADMINISTRATOR), idsKarcis, excJenisProduk, idsRegDJPPenunjangLab);
	}
}
