package com.jasamedika.medifirst2000.service.impl;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.dao.KelompokTransaksiDao;
import com.jasamedika.medifirst2000.dao.KomponenHargaDao;
import com.jasamedika.medifirst2000.dao.PegawaiDao;
import com.jasamedika.medifirst2000.dao.RuanganDao;
import com.jasamedika.medifirst2000.dao.RunningNumberDao;
import com.jasamedika.medifirst2000.dao.StrukHistoriDao;
import com.jasamedika.medifirst2000.dao.StrukPelayananDao;
import com.jasamedika.medifirst2000.dao.StrukVerifikasiDao;
import com.jasamedika.medifirst2000.dao.ViewGajiPegawaiDao;
import com.jasamedika.medifirst2000.entities.JenisGaji;
import com.jasamedika.medifirst2000.entities.KelompokTransaksi;
import com.jasamedika.medifirst2000.entities.KomponenHarga;
import com.jasamedika.medifirst2000.entities.Pegawai;
import com.jasamedika.medifirst2000.entities.PegawaiHistoriRekap;
import com.jasamedika.medifirst2000.entities.PegawaiHistoriRekapGaji;
import com.jasamedika.medifirst2000.entities.Ruangan;
import com.jasamedika.medifirst2000.entities.RunningNumber;
import com.jasamedika.medifirst2000.entities.StrukHistori;
import com.jasamedika.medifirst2000.entities.StrukPelayanan;
import com.jasamedika.medifirst2000.entities.StrukVerifikasi;
import com.jasamedika.medifirst2000.service.StrukHistoriService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.util.DateUtil;
import com.jasamedika.medifirst2000.util.ExcelGajiPegawai;
import com.jasamedika.medifirst2000.util.StringUtil;
import com.jasamedika.medifirst2000.vo.GajiPegawaiVO;
import com.jasamedika.medifirst2000.vo.JenisGajiVO;
import com.jasamedika.medifirst2000.vo.StrukHistoriVO;

@Service("StrukHistoriService")
public class StrukHistoriServiceImpl extends BaseVoServiceImpl implements StrukHistoriService {

	private final Logger LOG = LoggerFactory.getLogger(StrukHistoriServiceImpl.class);

	@Autowired
	private StrukHistoriDao strukHistoriDao;

	@Autowired
	private BaseConverterImpl<StrukHistoriVO, StrukHistori> strukHistoriConverter;

	@Autowired
	private BaseConverterImpl<JenisGajiVO, JenisGaji> jenisGajiConverter;

	@Autowired
	private RunningNumberDao runningNumberDao;

	@Autowired
	private KelompokTransaksiDao kelompokTransaksiDao;

	@Autowired
	private KomponenHargaDao komponenHargaDao;

	@Autowired
	private StrukPelayananDao strukPelayananDao;

	@Autowired
	private PegawaiDao pegawaiDao;

	@Autowired
	private RuanganDao ruanganDao;

	@Autowired
	private ViewGajiPegawaiDao viewGajiPegawaiDao;

	@Autowired
	private StrukVerifikasiDao strukVerifikasiDao;

	@Override
	@Transactional
	public Map<String, Object> save(StrukHistoriVO vo) {
		Map<String, Object> result = new HashMap<String, Object>();

		StrukHistori strukHistori = strukHistoriConverter.transferVOToModel(vo, new StrukHistori());

		// check ruangan
		Ruangan ruangan = ruanganDao.findById(213);
		if (ruangan != null) {
			strukHistori.setRuangan(ruangan);
		}

		// check kelompok transaksi (default: SDM)
		KelompokTransaksi kelompokTransaksi = kelompokTransaksiDao.findById(51);
		if (kelompokTransaksi != null) {
			strukHistori.setKelompokTransaksi(kelompokTransaksi);
		}

		if (CommonUtil.isNotNullOrEmpty(vo.getJenisGajiVO())) {
			strukHistori.setJenisGaji(jenisGajiConverter.transferVOToModel(vo.getJenisGajiVO(), new JenisGaji()));
		}

		if (CommonUtil.isNotNullOrEmpty(vo.getListGajiPegawai())) {
			strukHistori.setNonHistori(getRunningNumber("Struk Histori"));
			Set<PegawaiHistoriRekap> historiRekapList = new HashSet<>();
			Set<PegawaiHistoriRekapGaji> historiRekapGajiList = new HashSet<>();
			int counter = 0;

			for (ExcelGajiPegawai item : vo.getListGajiPegawai()) {
				// set period date (TglHistori) to current date, first date of
				// month (TglAwal) and last date of month (TglAhir)
				Date periodDate = DateUtil.fromExcelDateToDate(item.getBulan() + "-" + item.getTahun());
				Date startDate = DateUtil.getFirstLastDateOfMonth(periodDate, true);
				Date endDate = DateUtil.getFirstLastDateOfMonth(periodDate, false);

				strukHistori.setTglHistori(new Date());
				strukHistori.setTglAwal(startDate);
				strukHistori.setTglAhir(endDate);

				for (String kodeKolom : item.getKodeKolom()) {
					PegawaiHistoriRekapGaji rekapGaji = new PegawaiHistoriRekapGaji();
					rekapGaji.setStrukHistory(strukHistori);
					rekapGaji.setNoVerifikasi("1");// add by Arya 2017-03-23

					// periode per detail->PegawaiHistoriRekapGaji-reza
					if (CommonUtil.isNotNullOrEmpty(item.getBulan()) && CommonUtil.isNotNullOrEmpty(item.getTahun())) {
						String[] monthArray = DateUtil.INDONESIAN_MONTH;
						String bulan = monthArray[Integer.parseInt(item.getBulan().replace("0", "")) - 1];
						String tahun = item.getTahun();
						rekapGaji.setPeriode(bulan + "-" + tahun);
					}

					Pegawai pegawai = pegawaiDao.findOneByNipPns(item.getNip());
					if (pegawai != null) {
						rekapGaji.setPegawai(pegawai);
					} else {
						break;
					}
					// save history recapitulation
					if (kodeKolom.toLowerCase().equalsIgnoreCase("bersih")) {
						PegawaiHistoriRekap historiRekap = new PegawaiHistoriRekap();
						BigDecimal value = new BigDecimal(0);
						try {
							Field field = item.getClass().getField(kodeKolom);
							value = (BigDecimal) field.get(item);
						} catch (NoSuchFieldException | IllegalAccessException e) {
							LOG.debug(e.getMessage());
						}
						// set pegawai
						historiRekap.setPegawai(rekapGaji.getPegawai());
						historiRekap.setStrukHistory(strukHistori);
						historiRekap.setTotalHargaGajiAdd(value);
						//noVerifikasi(historiRekap);// add by Arya 2017-03-23

						StrukPelayanan strukPelayanan = new StrukPelayanan();
						strukPelayanan.setNostruk(getRunningNumberPelayanan("StrukPelayanan"));
						strukPelayanan.setTotalharusdibayar(value.doubleValue());
						strukPelayanan.setNoSBKLastId("");
						strukPelayanan.setVerifikasi("1");// add by Arya 2017-03-23
						// set pegawai
						strukPelayanan.setObjectPegawaiPenerimaId(pegawai.getId());
						strukPelayanan.setNamapegawaipenerima(rekapGaji.getPegawai().getNamaLengkap());
						strukPelayanan = strukPelayananDao.save(strukPelayanan);

						if (!strukPelayanan.getNoRec().isEmpty()) {
							// set relationships
							historiRekap.setNoStrukPelayanan(strukPelayanan);
							historiRekap.setNoStrukPelayananId(strukPelayanan.getNostruk());
							counter++;
						}
						result.put("importGaji.StrukPelayanan.totalCreated", counter);

						// Set<PegawaiHistoriRekap> historiRekapList = new
						// HashSet<>();
						historiRekapList.add(historiRekap);
						strukHistori.setPegawaiHistoriRekap(historiRekapList);

						continue;
					}

					// set komponen harga
					KomponenHarga komponenHarga = komponenHargaDao.findOneByKodeExternal(kodeKolom);
					if (komponenHarga != null) {
						rekapGaji.setKomponenHarga(komponenHarga);
					}
					// set harga satuan value from specified declared fields
					BigDecimal value = new BigDecimal(0);
					try {
						Field field = item.getClass().getField(kodeKolom);
						value = (BigDecimal) field.get(item);
						if (value != null) {
							rekapGaji.setHargaSatuan(value);
						}
					} catch (NoSuchFieldException | IllegalAccessException e) {
						LOG.debug(e.getMessage());
					}

					rekapGaji.setQtyKomponenHarga(1);
					historiRekapGajiList.add(rekapGaji);
				}
			}
			strukHistori.setRekapGaji(historiRekapGajiList);

			strukHistori = strukHistoriDao.save(strukHistori);
			if (!strukHistori.getNoRec().isEmpty()) {
				result.put("noRec.StrukHistori.importGaji", strukHistori.noRec);
				if (!strukHistori.getPegawaiHistoriRekap().isEmpty()) {
					for (PegawaiHistoriRekap rekap : strukHistori.getPegawaiHistoriRekap()) {
						if (!rekap.getNoRec().isEmpty()) {
							result.put("noRec.importGaji.PegawaiHistoriRekap", rekap.noRec);
						}
					}
				}
			} else {
				result.put("StrukHistori.ErrorMessage", "StrukHistory is not successfully created");
			}
		}

		return result;
	}

	@Override
	public List<Map<String, Object>> findPegawaiGajiSK(Integer idDetailKategoriPegawai) {
		return viewGajiPegawaiDao.findGajiPegawai(idDetailKategoriPegawai);
	}

	@Override
	@Transactional
	public Map<String, Object> saveGajiPegawai(StrukHistoriVO vo) {
		Map<String, Object> result = new HashMap<String, Object>();

		StrukHistori strukHistori = strukHistoriConverter.transferVOToModel(vo, new StrukHistori());

		// check ruangan
		Ruangan ruangan = ruanganDao.findById(213);
		if (ruangan != null) {
			strukHistori.setRuangan(ruangan);
		}

		// check kelompok transaksi (default: SDM)
		KelompokTransaksi kelompokTransaksi = kelompokTransaksiDao.findById(52);
		if (kelompokTransaksi != null) {
			strukHistori.setKelompokTransaksi(kelompokTransaksi);
		}

		if (CommonUtil.isNotNullOrEmpty(vo.getJenisGajiVO())) {
			strukHistori.setJenisGaji(jenisGajiConverter.transferVOToModel(vo.getJenisGajiVO(), new JenisGaji()));
		}

		// save gaji and struk histori
		if (!vo.getListKomponenGajiPegawai().isEmpty()) {
			strukHistori.setNonHistori(getRunningNumber("Struk Histori"));
			Set<PegawaiHistoriRekapGaji> historiRekapGajiList = new HashSet<>();
			int counter = 0;

			// set period date (TglHistori) to current date, first date of month
			// (TglAwal) and last date of month (TglAhir)
			Date startDate = DateUtil.getFirstLastDateOfMonth(vo.getTglAwal(), true);
			Date endDate = DateUtil.getFirstLastDateOfMonth(vo.getTglAwal(), false);

			for (GajiPegawaiVO komponenGaji : vo.getListKomponenGajiPegawai()) {
				PegawaiHistoriRekapGaji rekapGaji = new PegawaiHistoriRekapGaji();
				rekapGaji.setStrukHistory(strukHistori);

				strukHistori.setTglHistori(new Date());
				strukHistori.setTglAwal(startDate);
				strukHistori.setTglAhir(endDate);

				// set pegawai
				Pegawai pegawai = pegawaiDao.findOneByNipPns(komponenGaji.getNip());
				if (pegawai != null) {
					rekapGaji.setPegawai(pegawai);
				} else {
					break;
				}

				// save history recapitulation
				if (komponenGaji.getKomponenGaji().equalsIgnoreCase("gaji bersih")) {
					PegawaiHistoriRekap historiRekap = new PegawaiHistoriRekap();
					historiRekap.getNoStrukPelayananId();

					// set pegawai
					if (pegawai != null) {
						historiRekap.setPegawai(pegawai);
					}

					historiRekap.setStrukHistory(strukHistori);
					historiRekap.setTotalHargaGajiAdd(komponenGaji.getHargaSatuan());

					StrukPelayanan strukPelayanan = new StrukPelayanan();
					strukPelayanan.setNostruk(getRunningNumberPelayanan("StrukPelayanan"));
					strukPelayanan.setTotalharusdibayar(komponenGaji.getHargaSatuan().doubleValue());
					strukPelayanan.setNoSBKLastId("");

					// set pegawai penerima
					strukPelayanan.setObjectPegawaiPenerimaId(pegawai.getId());
					strukPelayanan.setNamapegawaipenerima(pegawai.getNamaLengkap());
					strukPelayanan = strukPelayananDao.save(strukPelayanan);

					if (!strukPelayanan.getNoRec().isEmpty()) {
						// set relationships
						historiRekap.setNoStrukPelayanan(strukPelayanan);
						historiRekap.setNoStrukPelayananId(strukPelayanan.getNostruk());
						counter++;
					}
					result.put("StrukPelayanan.gajiPegawai.totalCreated", counter);

					Set<PegawaiHistoriRekap> historiRekapList = new HashSet<>();
					historiRekapList.add(historiRekap);
					strukHistori.setPegawaiHistoriRekap(historiRekapList);

					continue;
				}

				// set komponen harga
				KomponenHarga komponenHarga = komponenHargaDao.findOne(komponenGaji.getIdKomponenGaji());
				if (komponenHarga != null) {
					rekapGaji.setKomponenHarga(komponenHarga);
				}
				// set harga satuan value from specified declared fields
				rekapGaji.setHargaSatuan(komponenGaji.getHargaSatuan());

				rekapGaji.setQtyKomponenHarga(1);
				historiRekapGajiList.add(rekapGaji);
			}

			strukHistori.setRekapGaji(historiRekapGajiList);

			strukHistori = strukHistoriDao.save(strukHistori);
			if (!strukHistori.getNoRec().isEmpty()) {
				result.put("noRec.StrukHistori.gajiPegawai", strukHistori.noRec);
				if (!strukHistori.getPegawaiHistoriRekap().isEmpty()) {
					for (PegawaiHistoriRekap rekap : strukHistori.getPegawaiHistoriRekap()) {
						if (!rekap.getNoRec().isEmpty()) {
							result.put("noRec.gajiPegawai.PegawaiHistoriRekap", rekap.noRec);
						}
					}
				}
			} else {
				result.put("StrukHistori.ErrorMessage", "StrukHistory is not successfully created");
			}
		}

		return result;
	}

	// add by Arya 2017-03-23
	private Map<String, Object> noVerifikasi(PegawaiHistoriRekap historiRekap) {

		Map<String, Object> result = new HashMap<String, Object>();

		try {
			System.out.println("=======START SAVE STRUK VERIFIKASI=======");

			String[] a = GetSettingDataFixed("RuanganVerifikasiPembayaranGajiPegawai").split(",");
			String b = GetSettingDataFixed("KdRuanganAkuntansi");

			List<Map<String, Object>> map = strukPelayananDao.getRuanganVerifikasiPembayaranHutang();
			String[] ruanganSplit = map.get(0).get("nilaiField").toString().split(",");

			Set<StrukVerifikasi> list = new HashSet<>();
			StrukVerifikasi strukVerifikasi = new StrukVerifikasi();

			String tempString = "";

			for (int i = 0; i < a.length; i++) {
				StrukVerifikasi strukVerif = new StrukVerifikasi();
				strukVerif.setNoUrutRuangan((i + 1) + "");
				strukVerif.setKelompokTransaksi(kelompokTransaksiDao.findById(
						Integer.parseInt((String) this.GetSettingDataFixed("KdKelompokTransaksiGajiPegawaiNonPns"))));
				strukVerif.setTglverifikasi(DateUtil.getShortDate());
				strukVerifikasi.setTglverifikasi(DateUtil.getShortDate());
				strukVerifikasi.setKelompokTransaksi(kelompokTransaksiDao.findById(
						Integer.parseInt((String) this.GetSettingDataFixed("KdKelompokTransaksiGajiPegawaiNonPns"))));

				final List<String> temp = new ArrayList<String>();
				Collections.addAll(temp, ruanganSplit);
				temp.remove(tempString);
				ruanganSplit = temp.toArray(new String[temp.size()]);

				for (String idRuangan : ruanganSplit) {
					Ruangan ruangan = new Ruangan();
					ruangan.setId(Integer.parseInt(idRuangan));
					strukVerif.setRuangan(ruangan);
					if (idRuangan.equals("61") && b.equals("61")) {
						strukVerif.setNoverifikasi("VA" + generateNoVerifikasi());
						list.add(strukVerif);
						tempString = idRuangan;
						break;
					} else {
						strukVerif.setNoverifikasi("VO" + generateNoVerifikasi());
						list.add(strukVerif);
						tempString = idRuangan;
						break;
					}
				}
				strukVerifikasi.setStrukVerifikasiSet(list);
				historiRekap.setStrukVerifikasi(strukVerifikasi);

				if (CommonUtil.isNotNullOrEmpty(strukVerif)) {
					strukVerif.setStrukVerifikasi(strukVerifikasi);
				}
			}

			StrukVerifikasi model = strukVerifikasiDao.save(strukVerifikasi);
			result.put("noRecStrukVerifikasi", model.getNoRec());

			System.out.println("=======END SAVE STRUK VERIFIKASI=======");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	public String generateNoVerifikasi() {

		Date dateNow = new Date();
		Integer month = DateUtil.getMonthFromDate(dateNow);
		Integer year = DateUtil.getYearFromDate(dateNow);
		Long count = strukVerifikasiDao.count();

		String monthNow = month.toString();
		String yearNow = year.toString().substring(2, 4);
		String noSbk = null;

		count++;
		if (count.toString().length() == 1) {
			noSbk = "000000";
		} else if (count.toString().length() == 2) {
			noSbk = "000000";
		} else if (count.toString().length() == 3) {
			noSbk = "000000";
		} else if (count.toString().length() == 4) {
			noSbk = "000000";
		} else if (count.toString().length() == 5) {
			noSbk = "000000";
		} else if (count.toString().length() == 6) {
			noSbk = "000000";
		}
		if (monthNow.length() == 1)
			monthNow = "0" + monthNow;

		return yearNow + monthNow + noSbk + count;
	}

	@Override
	public Map<String, Object> findUangMakan() {
		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(), 10);
		runningNumberDao.save(runningNumber);
		return noOrderIntern;
	}

	@Transactional(readOnly = false)
	private String getRunningNumberPelayanan(String kegunaan) {
		RunningNumber runningNumber = runningNumberDao.findByResetAndKegunaan("0", kegunaan);
		if (runningNumber == null) {
			runningNumber = new RunningNumber();
			runningNumber.setKegunaan(kegunaan);
			runningNumber.setReset("0");
			runningNumber.setNomerTerbaru((Integer) 0);
		}
		Integer number = (runningNumber.getNomerTerbaru() + (Integer) 1);
		runningNumber.setNomerTerbaru(runningNumber.getNomerTerbaru() + (Integer) 1);
		String noOrderIntern = StringUtil.formatNumber(number.toString(), 10);
		return noOrderIntern;
	}

}
