package com.jasamedika.medifirst2000.service.impl;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
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.apache.commons.collections.IteratorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.jasamedika.medifirst2000.converter.BaseConverterImpl;
import com.jasamedika.medifirst2000.converter.LoginUserAuthConverter;
import com.jasamedika.medifirst2000.converter.LoginUserConverter;
import com.jasamedika.medifirst2000.dao.HistoryLoginModulAplikasiDao;
import com.jasamedika.medifirst2000.dao.LoginUserDao;
import com.jasamedika.medifirst2000.dao.MapPegawaiToModulAplikasiDao;
import com.jasamedika.medifirst2000.entities.HistoryLoginModulAplikasi;
import com.jasamedika.medifirst2000.entities.KelompokUser;
import com.jasamedika.medifirst2000.entities.LoginUser;
import com.jasamedika.medifirst2000.entities.MapLoginUserToRuangan;
import com.jasamedika.medifirst2000.entities.MapPegawaiToModulAplikasi;
import com.jasamedika.medifirst2000.entities.ModulAplikasi;
import com.jasamedika.medifirst2000.entities.Pegawai;
import com.jasamedika.medifirst2000.entities.Ruangan;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.LoginUserService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.util.PasswordUtil;
import com.jasamedika.medifirst2000.vo.KelompokUserVO;
import com.jasamedika.medifirst2000.vo.LoginUserVO;
import com.jasamedika.medifirst2000.vo.MapLoginUserToRuanganVO;
import com.jasamedika.medifirst2000.vo.MapPegawaiToModulAplikasiVO;
import com.jasamedika.medifirst2000.vo.ModulAplikasiVO;
import com.jasamedika.medifirst2000.vo.PegawaiVO;
import com.jasamedika.medifirst2000.vo.RuanganVO;
import com.jasamedika.medifirst2000.vo.custom.AuthVO;

@Service("LoginUserService")
public class LoginUserServiceImpl extends BaseVoServiceImpl implements LoginUserService {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(LoginUserServiceImpl.class);

	@Autowired
	private LoginUserDao loginUserDao;
	
	@Autowired
	private MapPegawaiToModulAplikasiDao mapPegawaiToModulAplikasiDao;

	@Autowired
	private LoginUserAuthConverter loginUserAuthConverter;

	@Autowired
	private LoginUserConverter loginUserConverter;
	
	@Autowired
	private BaseConverterImpl<LoginUserVO, LoginUser> loginUserConverters;
	
	@Autowired
	private BaseConverterImpl<PegawaiVO, Pegawai> pegawaiConverter;
	
	@Autowired
	private BaseConverterImpl<KelompokUserVO, KelompokUser> kelompokUserConverter;
	
	@Autowired
	private BaseConverterImpl<MapPegawaiToModulAplikasiVO, MapPegawaiToModulAplikasi> mapPegawaiToModulAplikasiConverter;
	
	@Autowired
	private BaseConverterImpl<ModulAplikasiVO, ModulAplikasi> modulAplikasiConverter;
	
	@Autowired
	private BaseConverterImpl<MapLoginUserToRuanganVO, MapLoginUserToRuangan> mapLoginUserToRuanganConverter;
	
	@Autowired
	private BaseConverterImpl<RuanganVO, Ruangan> ruanganConverter;
	
	@Autowired
	private HistoryLoginModulAplikasiDao historyLoginModulAplikasiDao;
	
	@Override
	public Integer getCurrentRuanganId() {
		Ruangan ruangan = getCurrentRuangan();
		if (CommonUtil.isNullOrEmpty(ruangan)){
			return 0;
		}
		
		return ruangan.getId();
	}
	
	@Override
	public Ruangan getCurrentRuangan(){
		
		LoginUser loginUser = getLoginUser();
		
		Ruangan ruangan;
		
		List<HistoryLoginModulAplikasi> historyS  = historyLoginModulAplikasiDao.findCurrentRuangan(loginUser.getNamaUser(), new Date());
		
		if (CommonUtil.isNullOrEmpty(historyS) || CommonUtil.isNullOrEmpty(historyS.get(0).getRuanganUserId())){
			ruangan = loginUser.getPegawai().getRuangan();
		} else {
			ruangan = historyS.get(0).getRuanganUser();
		}
		
		return ruangan;
	}
	
	public List<LoginUser> findByNamaUser(String namaUser){
		return loginUserDao.findByNamaUser(namaUser);
	}
	
	@Override
	@Transactional(readOnly = false)
	public LoginUserVO add(LoginUserVO vo) throws JpaSystemException, ServiceVOException {
		// convert to model and call repository
		LoginUser loginUser = new LoginUser();
		loginUser = loginUserConverter.transferVOToModel(vo, loginUser);

		PasswordUtil passwordUtil = new PasswordUtil();
		try {
			loginUser.setKataSandi(passwordUtil.encryptPassword(loginUser.getKataSandi()));
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		LoginUser resultModel = loginUserDao.save(loginUser);

		// return VO
		LoginUserVO resultVo = new LoginUserVO();
		resultVo = loginUserConverter.transferModelToVO(resultModel, resultVo);

		return resultVo;
	}
	
	@Override
	@Transactional(readOnly = false)
	public LoginUserVO update(LoginUserVO vo) throws JpaSystemException, ServiceVOException {

		//Alter Syamsu
		LoginUser loginUserLama = loginUserDao.findOne(vo.getId());
		
		PasswordUtil passwordUtil = new PasswordUtil();
		

		loginUserConverter.transferVOToModel(vo, loginUserLama);
		
		try {
			loginUserLama.setKataSandi(passwordUtil.encryptPassword(loginUserLama.getKataSandi()));
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		loginUserDao.save(loginUserLama);

		// return VO
		LoginUserVO resultVo = new LoginUserVO();
		resultVo = loginUserConverter.transferModelToVO(loginUserLama, resultVo);

		return resultVo;
	}

	@Override
	@Transactional(readOnly = false)
	public Boolean delete(Integer key) throws JpaSystemException {
		if (loginUserDao.exists(key)) {
			loginUserDao.delete(key);
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public LoginUserVO findById(Integer key) throws JpaSystemException {
		LoginUser loginUser = loginUserDao.findOne(key);
		if (loginUser == null) {
			return null;
		}
		LoginUserVO loginUserVO = new LoginUserVO();
		loginUserVO = loginUserConverter.transferModelToVO(loginUser, loginUserVO);
		return loginUserVO;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public List<LoginUserVO> findAll() throws JpaSystemException {

		List<LoginUser> loginUserList = IteratorUtils.toList(loginUserDao.findAll().iterator());

		List<LoginUserVO> loginUserVOList = new ArrayList<LoginUserVO>();
		loginUserConverter.transferListOfModelToListOfVO(loginUserList, loginUserVOList);

		return loginUserVOList;
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public Map<String, Object> findAllWithPageAndLimitAndSortByAndDirectionParameter(Integer page, Integer limit,
			String sort, String dir) {
		return null;
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public LoginUserVO signIn(AuthVO authVO) throws Exception {

		List<LoginUser> loginUsers = loginUserDao.findByNamaUser(authVO.getNamaUser());
		if (!loginUsers.isEmpty()) {

			LoginUser loginUser = loginUsers.get(0);
			PasswordUtil passwordUtil = new PasswordUtil();
			Boolean isValidPassword = false;
			try {
				isValidPassword = passwordUtil.isPasswordEqual(authVO.getKataSandi(), loginUser.getKataSandi());
			} catch (IOException ioe) {
				LOGGER.error("Password not match : " + ioe.getMessage());
				return null;
			}

			if (!isValidPassword) {
				return null;
			}
			// to do validasi yang advanced di sini

			LoginUserVO vo = new LoginUserVO();
			loginUserAuthConverter.transferModelToVO(loginUser, vo);
			return vo;

		} else {
			throw new RuntimeException("User account is unauthorized : username : " + authVO.getNamaUser());
		}
	}
	
	@Override
	public  LoginUser getLoginUser(){
		List<LoginUser> loginUser = null;
        try {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String namaUser = principal.toString();
            loginUser = loginUserDao.findByNamaUser(namaUser);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return loginUser.get(0);
    }

	@Override
	public Map<String, Object> getAllUser() {
		Map<String, Object> result = new HashMap<String, Object>();
		List<LoginUser> list = new ArrayList<LoginUser>();
		list = (List<LoginUser>) loginUserDao.findAllUser();
		if(CommonUtil.isNotNullOrEmpty(list)){
			result.put("data", list);
			result.put("dataFound", true);
		}
		else{
			result.put("dataFound", false);
		}
		return result;
	}

	
	//Reza
	//-----------------------------------------------------------------------------------------------

	@Override
	public Map<String, Object> getLoadData(){
		Map<String, Object> result = new HashMap<String, Object>();
		//--------------------------------------------------------------------------
		List<Map<String, Object>> listPegawai = loginUserDao.listPegawai();
		if(CommonUtil.isNotNullOrEmpty(listPegawai)){
			result.put("listPegawai", listPegawai);
		}
		//--------------------------------------------------------------------------
		List<Map<String, Object>> listKelompokUser = loginUserDao.listKelompokUser();
		if(CommonUtil.isNotNullOrEmpty(listKelompokUser)){
			result.put("listKelompokUser", listKelompokUser);
		}
		//--------------------------------------------------------------------------
		List<Map<String, Object>> listSideMenu = getListSideMenu();
		if(CommonUtil.isNotNullOrEmpty(listSideMenu)){
			result.put("listSideMenu", listSideMenu);
		}
		return result;
	}
	
	@Override
	public List<Map<String, Object>> getListSideMenu(){
		List<Map<String, Object>> listSideMenu = new ArrayList<>();
		try{
			for(Map<String, Object> ruangan : loginUserDao.listRuangan()){
				Map<String, Object> mapRuangan = new HashMap<>();
				
				if(CommonUtil.isNotNullOrEmpty(ruangan)){
					mapRuangan.put("ruanganId", ruangan.get("id"));
					mapRuangan.put("namaRuangan", ruangan.get("namaRuangan"));
					
					List<Map<String, Object>> listModul = new ArrayList<>();
					for(Map<String, Object> modul : loginUserDao.getModulByDepartemen((Integer)ruangan.get("departemenId"))){
						Map<String, Object> mapModul = new HashMap<>();
						
						if(CommonUtil.isNotNullOrEmpty(modul)){
							mapModul.put("modulId", modul.get("id"));
							mapModul.put("namaModul", modul.get("modulAplikasi"));
							mapModul.put("noUrut", modul.get("modulNoUrut"));
							
							List<Map<String, Object>> listObjectModulHead = new ArrayList<>();
							for(Map<String, Object> objectModulHead : loginUserDao.getObjectModulHeadByModul((Integer)modul.get("id"))){
								Map<String, Object> mapObjectModulHead = new HashMap<>();
								
								if(CommonUtil.isNotNullOrEmpty(objectModulHead)){
									mapObjectModulHead.put("objectModulHeadId", objectModulHead.get("id"));
									mapObjectModulHead.put("namaObjekModulHead", objectModulHead.get("objekModulAplikasi"));
									mapObjectModulHead.put("linkAplikasi", objectModulHead.get("alamatUrlForm"));
									mapObjectModulHead.put("noUrut", objectModulHead.get("objekModulNoUrut"));
									
									List<Map<String, Object>> listObjectModul = new ArrayList<>();
									for(Map<String, Object> objectModul: loginUserDao.getModulByModulHead((Integer)objectModulHead.get("id"))){
										Map<String, Object> mapObjectModul = new HashMap<>();
										
										if(CommonUtil.isNotNullOrEmpty(objectModul)){
											mapObjectModul.put("objectModulId", objectModul.get("id"));
											mapObjectModul.put("namaObjekModul", objectModul.get("objekModulAplikasi"));
											mapObjectModul.put("linkAplikasi", objectModul.get("alamatUrlForm"));
											mapObjectModul.put("noUrut", objectModul.get("objekModulNoUrut"));
										}
										if(CommonUtil.isNotNullOrEmpty(mapObjectModul)){
											listObjectModul.add(mapObjectModul);
										}
									}
									if(CommonUtil.isNotNullOrEmpty(listObjectModul)){
										mapObjectModulHead.put("listObjectModul", listObjectModul);
									}
								}
								if(CommonUtil.isNotNullOrEmpty(mapObjectModulHead)){
									listObjectModulHead.add(mapObjectModulHead);
								}
							}
							if(CommonUtil.isNotNullOrEmpty(listObjectModulHead)){
								mapModul.put("listObjectModulHead", listObjectModulHead);
							}
						}
						if(CommonUtil.isNotNullOrEmpty(mapModul)){
							listModul.add(mapModul);
						}
					}
					if(CommonUtil.isNotNullOrEmpty(listModul)){
						mapRuangan.put("listModul", listModul);
					}
				}
				if(CommonUtil.isNotNullOrEmpty(mapRuangan)){
					listSideMenu.add(mapRuangan);
				}
			}
		}catch (Exception ex){
			ex.printStackTrace();
		}
		return listSideMenu;
	}
	
	@Override
	public Map<String, Object> saveLoginUser(LoginUserVO vo){
		Map<String, Object> result = new HashMap<>();
		
		if (CommonUtil.isNotNullOrEmpty(vo.getNamaUser())) {
			List<LoginUser> users = loginUserDao.findByNamaUser(vo.getNamaUser());
			if (!users.isEmpty()) {
				throw new ServiceVOException("Nama user sudah ada, ganti atau pakai nama user yang lain");
			}
		}
		
		LoginUser loginUser = new LoginUser();
		if(CommonUtil.isNotNullOrEmpty(vo)){
			loginUser = loginUserConverters.transferVOToModel(vo, new LoginUser());
			loginUser.setKdProfile((short) 0);
			loginUser.setStatusEnabled(true);
			loginUser.setKodeExternal("");
			loginUser.setNamaExternal(vo.getNamaUser());
			loginUser.setReportDisplay(vo.getNamaUser());
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getKelompokUser())){
			loginUser.setKelompokUser(kelompokUserConverter.transferVOToModel(vo.getKelompokUser(), new KelompokUser()));
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getKataSandi())){
			try {
				loginUser.setKataSandi(new PasswordUtil().encryptPassword(vo.getKataSandi()));
			} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getPegawai())){
			loginUser.setPegawai(pegawaiConverter.transferVOToModel(vo.getPegawai(), new Pegawai()));
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getMapLoginUserToRuanganSet())){
			Set<MapLoginUserToRuangan> loginUserToRuanganSet = new HashSet<>();
			
			for(MapLoginUserToRuanganVO loginUserToRuanganVO : vo.getMapLoginUserToRuanganSet()){
				
				MapLoginUserToRuangan mapLoginUserToRuangan = new MapLoginUserToRuangan();
				if(CommonUtil.isNotNullOrEmpty(loginUserToRuanganVO)){
					mapLoginUserToRuangan = mapLoginUserToRuanganConverter.transferVOToModel(loginUserToRuanganVO, new MapLoginUserToRuangan());
					mapLoginUserToRuangan.setLoginUser(loginUser);
				}
				if(CommonUtil.isNotNullOrEmpty(loginUserToRuanganVO.getRuangan())){
					mapLoginUserToRuangan.setRuangan(ruanganConverter.transferVOToModel(loginUserToRuanganVO.getRuangan(), new Ruangan()));
				}
				if(CommonUtil.isNotNullOrEmpty(mapLoginUserToRuangan)){
					loginUserToRuanganSet.add(mapLoginUserToRuangan);
				}
			}
			if(CommonUtil.isNotNullOrEmpty(loginUserToRuanganSet)){
				loginUser.setMapLoginUserToRuanganSet(loginUserToRuanganSet);
			}
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getMapPegawaiToModulAplikasiSet())){
			for(MapPegawaiToModulAplikasiVO pegawaiToModulVO : vo.getMapPegawaiToModulAplikasiSet()){
				
				MapPegawaiToModulAplikasi mapPegawaiToModulAplikasi = new MapPegawaiToModulAplikasi();
				if(CommonUtil.isNotNullOrEmpty(pegawaiToModulVO)){
					mapPegawaiToModulAplikasi = mapPegawaiToModulAplikasiConverter.transferVOToModel(pegawaiToModulVO, new MapPegawaiToModulAplikasi());
					mapPegawaiToModulAplikasi.setPegawai(pegawaiConverter.transferVOToModel(vo.getPegawai(), new Pegawai()));
				}
				if(CommonUtil.isNotNullOrEmpty(pegawaiToModulVO.getModulAplikasi())){
					mapPegawaiToModulAplikasi.setModulAplikasi(modulAplikasiConverter.transferVOToModel(pegawaiToModulVO.getModulAplikasi(), new ModulAplikasi()));
				}
				if(CommonUtil.isNotNullOrEmpty(mapPegawaiToModulAplikasi)){
					mapPegawaiToModulAplikasiDao.save(mapPegawaiToModulAplikasi);
				}
			}
			
		}
		if(CommonUtil.isNotNullOrEmpty(loginUser)){
			LoginUser loginUserResult = loginUserDao.save(loginUser);
			result.put("id", loginUserResult.getId());
		}
		return result;
	}
	
	@Override
	public Map<String, Object> getListRuangan(Integer loginUserId){
		Map<String, Object> result = new HashMap<>();
		List<Map<String, Object>> listRuangan = loginUserDao.getListRuangan(loginUserId);
		if(CommonUtil.isNotNullOrEmpty(listRuangan)){
			result.put("listRuangan", listRuangan);
		}
		return result;
	}
	
	@Override
	public Map<String, Object> getListModulAplikasi(Integer pegawaiId){
		Map<String, Object> result = new HashMap<>();
		List<Map<String, Object>> listModulAplikasi = loginUserDao.getListModulAplikasi(pegawaiId);
		if(CommonUtil.isNotNullOrEmpty(listModulAplikasi)){
			result.put("listModulAplikasi", listModulAplikasi);
		}
		return result;
	}
	
	@Override
	public List<Map<String, Object>> getListObjectModulAplikasi(Integer modulAplikasiId){
		List<Map<String, Object>> result = new ArrayList<>();
//		for(Map<String, Object> objectModulHead : loginUserDao.getObjectModulHeadByModul(modulAplikasiId)){
//			Map<String, Object> parent = new HashMap<>();
//			
//			if(CommonUtil.isNotNullOrEmpty(objectModulHead)){
//				parent.put("name", objectModulHead.get("objekModulAplikasi"));
//				parent.put("noUrut", objectModulHead.get("objekModulNoUrut"));
//				
//				List<Map<String, Object>> listObjectModul = loginUserDao.getModulByModulHead((Integer)objectModulHead.get("id"));
//				if(CommonUtil.isNullOrEmpty(listObjectModul)){
//					parent.put("link", objectModulHead.get("alamatUrlForm"));
//				}
//				
//				List<Map<String, Object>> listChildren = new ArrayList<>();
//				for(Map<String, Object> objectModul: listObjectModul){
//					Map<String, Object> children = new HashMap<>();
//					
//					if(CommonUtil.isNotNullOrEmpty(objectModul)){
//						children.put("name", objectModul.get("objekModulAplikasi"));
//						children.put("link", objectModul.get("alamatUrlForm"));
//						children.put("noUrut", objectModul.get("objekModulNoUrut"));
//					}
//					if(CommonUtil.isNotNullOrEmpty(children)){
//						listChildren.add(children);
//					}
//				}
//				if(CommonUtil.isNotNullOrEmpty(listChildren)){
//					parent.put("children", listChildren);
//				}
//			}
//			if(CommonUtil.isNotNullOrEmpty(parent)){
//				result.add(parent);
//			}
//		}
		return result;
	}
	
	@Override
	public Map<String, Object> saveUpdateLoginUser(LoginUserVO vo){
		Map<String, Object> result = new HashMap<>();
		
		if(CommonUtil.isNotNullOrEmpty(vo)) {
			LoginUser loginUser = new LoginUser();
			
			if(CommonUtil.isNotNullOrEmpty(vo.getId())) {
				loginUser = setLoginUser(vo);
				if(CommonUtil.isNotNullOrEmpty(loginUser)) {
					LoginUser loginUserResult = loginUserDao.save(loginUser);
					result.put("namaUser", loginUserResult.getNamaUser());
					result.put("statusError", "");
				}
			} else {
				List<LoginUser> users = loginUserDao.findByNamaUser(vo.getNamaUser());
				
				if(CommonUtil.isNotNullOrEmpty(users)) {
					result.put("statusError", "Nama user sudah ada, silahkan input nama user lainya");
				} else {
					loginUser = setLoginUser(vo);
					if(CommonUtil.isNotNullOrEmpty(loginUser)) {
						LoginUser loginUserResult = loginUserDao.save(loginUser);
						result.put("namaUser", loginUserResult.getNamaUser());
						result.put("statusError", "");
					}
				}
			}
		}
		return result;
	}

	@Override
	public LoginUser setLoginUser(LoginUserVO vo) {
		LoginUser loginUser;

		if(CommonUtil.isNotNullOrEmpty(vo.getId())) {
			loginUser = loginUserDao.findOne(vo.getId());
		} else {
			loginUser = loginUserConverter.transferVOToModel(vo, new LoginUser());
		}
		if(CommonUtil.isNotNullOrEmpty(vo)){
			loginUser.setKdProfile((short) 0);
			loginUser.setStatusEnabled(true);
			loginUser.setKodeExternal("");
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getNamaUser())) {
			loginUser.setNamaUser(vo.getNamaUser());
			loginUser.setNamaExternal(vo.getNamaUser());
			loginUser.setReportDisplay(vo.getNamaUser());
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getKelompokUser())){
			loginUser.setKelompokUser(kelompokUserConverter.transferVOToModel(vo.getKelompokUser(), new KelompokUser()));
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getKataSandi())){
			try {
				loginUser.setKataSandi(new PasswordUtil().encryptPassword(vo.getKataSandi()));
			} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		if(CommonUtil.isNotNullOrEmpty(vo.getPegawai())){
			loginUser.setPegawai(pegawaiConverter.transferVOToModel(vo.getPegawai(), new Pegawai()));
		}
		return loginUser;
	}
}
