package com.jasamedika.medifirst2000.controller;

import com.jasamedika.medifirst2000.constants.Constants;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.logging.hibernate.async.LoggingSystemAsynchronous;
import com.jasamedika.medifirst2000.notification.MessagePublisher;
import com.jasamedika.medifirst2000.security.model.UserAuthentication;
import com.jasamedika.medifirst2000.security.service.TokenAuthenticationService;
import com.jasamedika.medifirst2000.service.ActivityPegawaiService;
import com.jasamedika.medifirst2000.service.JadwalDokterService;
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.rest.RestUtil;
import com.jasamedika.medifirst2000.vo.LoginUserVO;
import com.jasamedika.medifirst2000.vo.custom.AuthVO;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Controller class for Authenticate Business
 * 
 * @author Roberto
 */
@RestController
@RequestMapping("/auth")
public class AuthenticateController {

	private static final Logger LOGGER = getLogger(AuthenticateController.class);

	protected Map<String, String> mapHeaderMessage = new HashMap<>();

	@Autowired
	MessagePublisher<String, Object> messagePublisher;

	@Autowired
	LoggingSystemAsynchronous loggingSystemAsynchronous;

	@Autowired
	private LoginUserService loginUserService;

	@Autowired
	private ActivityPegawaiService activityPegawaiService;

	@Autowired
	public JadwalDokterService jadwalDokterService;

	@Autowired
	private TokenAuthenticationService tokenAuthenticationService;

	@RequestMapping(value = "/history", method = RequestMethod.GET)
	@ResponseBody
	public ResponseEntity<Object> GetHistory(@RequestParam(value = "dateStart", required = false) String dateStart,
			@RequestParam(value = "dateEnd", required = false) String dateEnd,
			@RequestParam(value = "top", required = false, defaultValue = "0") Integer top, HttpServletRequest request,
			HttpServletResponse httpResponse) {
		if (top == 0)
			top = Integer.MAX_VALUE;
		Date start = DateUtil.toDate(dateStart);
		Date until = DateUtil.toDate(dateEnd);
		try {
			Object data = JsonUtil.ToMaps(activityPegawaiService.getData(start, until, top));
			return RestUtil.getJsonResponse(data, HttpStatus.OK, mapHeaderMessage);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new ServiceVOException(e.getMessage());
		}
	}

	@RequestMapping(value = "/sign-in", method = RequestMethod.POST)
	@ResponseBody
	public ResponseEntity<LoginUserVO> signIn(@RequestBody AuthVO vo, HttpServletRequest request,
			HttpServletResponse httpResponse) {
		if (vo.getNamaUser() == null || vo.getKataSandi() == null) {
			this.mapHeaderMessage.put(Constants.MessageInfo.ERROR_MESSAGE, "Username or Password is empty");
			return RestUtil.getJsonHttpStatus(HttpStatus.BAD_REQUEST, mapHeaderMessage);
		}

		LOGGER.info("starting sign-in {}", vo.getNamaUser() + " at " + DateUtil.getIndonesianStringDate(new Date()));

		try {
			mapHeaderMessage = new HashMap<>();
			LoginUserVO loginUserVo = loginUserService.signIn(vo);
			if (loginUserVo == null) {
				this.mapHeaderMessage.put(Constants.MessageInfo.ERROR_MESSAGE, "Invalid Username or Password");
				return RestUtil.getJsonHttpStatus(HttpStatus.NOT_ACCEPTABLE, mapHeaderMessage);
			}
			GrantedAuthority authority = new SimpleGrantedAuthority("USER");
			String token = tokenAuthenticationService.addAuthentication(new UserAuthentication(new User(loginUserVo.getNamaUser(), loginUserVo.getKataSandi(),
							Collections.singletonList(authority))));
			boolean isSupervising = request.getHeader(Constants.HttpHeader.SUPERVISING) != null;
			if (isSupervising) { // supervising login
				mapHeaderMessage.put("X-AUTH-SUPERVISOR-TOKEN", token);
				activityPegawaiService.record(loginUserVo.getPegawai(), new Date(), "Supervising Login");
			} else { // normal login
				Map<String, Object> data = new HashMap<>();
				if (loginUserVo.getPegawai().getJenisPegawai() != null && loginUserVo.getPegawai().getJenisPegawai()
						.getId() == Integer.parseInt(GetSettingDataFixed("KdJenisPegawaiDokter")))
					jadwalDokterService.CheckJadwalDokter(new Date(), loginUserVo.getPegawai());
				mapHeaderMessage.put("X-AUTH-TOKEN", token);
				activityPegawaiService.record(loginUserVo.getPegawai(), new Date(), "Behasil Login Ke System");
				messagePublisher.sendDirectNotification(data);
				Integer idPegawai = 0;
				if (CommonUtil.isNotNullOrEmpty(loginUserVo.getPegawai()))
					idPegawai = loginUserVo.getPegawai().getId();
				loggingSystemAsynchronous.saveSignInLog(0, 0, loginUserVo.getNamaUser(), idPegawai);
			}
			return RestUtil.getJsonResponse(loginUserVo, HttpStatus.OK, mapHeaderMessage);
		} catch (Exception ex) {
			LOGGER.error("Signing-in error {}", ex.getMessage());

			return RestUtil.getJsonHttpStatus(HttpStatus.UNAUTHORIZED);
		}
	}

	public String GetSettingDataFixed(String prefix) {
		return activityPegawaiService.GetSettingDataFixed(prefix);
	}

	@RequestMapping(value = "/sign-out", method = RequestMethod.POST)
	@ResponseBody
	public ResponseEntity<AuthVO> signOut(@RequestBody AuthVO vo, HttpServletResponse httpResponse) {
		LoginUserVO loginUserVO = loginUserService.findById(vo.getId());

		LOGGER.info("starting sign-out {}",
				loginUserVO.getNamaUser() + " at " + DateUtil.getIndonesianStringDate(new Date()));

		Integer idPegawai = 0;
		if (CommonUtil.isNotNullOrEmpty(loginUserVO.getPegawai()))
			idPegawai = loginUserVO.getPegawai().getId();
		loggingSystemAsynchronous.saveSignOutLog(loginUserVO.getNamaUser(), idPegawai);
		return RestUtil.getJsonResponse(vo, HttpStatus.OK);
	}

	@RequestMapping(value = "/sign-in-mobile", method = RequestMethod.POST)
	@ResponseBody
	public ResponseEntity<Map<String, Object>> signInMobile(@RequestBody AuthVO vo, HttpServletRequest request,
			HttpServletResponse httpResponse) {
		if (vo.getNamaUser() == null || vo.getKataSandi() == null) {
			this.mapHeaderMessage.put(Constants.MessageInfo.ERROR_MESSAGE, "Username or Password is empty");
			return RestUtil.getJsonHttpStatus(HttpStatus.BAD_REQUEST, mapHeaderMessage);
		}

		LOGGER.info("starting sign-in-mobile {}",
				vo.getNamaUser() + " at " + DateUtil.getIndonesianStringDate(new Date()));

		try {
			mapHeaderMessage = new HashMap<>();
			LoginUserVO loginUserVo = loginUserService.signIn(vo);
			if (loginUserVo == null) {
				this.mapHeaderMessage.put(Constants.MessageInfo.ERROR_MESSAGE, "Invalid Username or Password");
				return RestUtil.getJsonHttpStatus(HttpStatus.NOT_ACCEPTABLE, mapHeaderMessage);
			}
			GrantedAuthority authority = new SimpleGrantedAuthority("USER");
			String token = tokenAuthenticationService.addAuthentication(new UserAuthentication(new User(loginUserVo.getNamaUser(), loginUserVo.getKataSandi(),
							Collections.singletonList(authority))));
			boolean isSupervising = request.getHeader(Constants.HttpHeader.SUPERVISING) != null;
			if (isSupervising) { // supervising login
				mapHeaderMessage.put("X-AUTH-SUPERVISOR-TOKEN", token);
				activityPegawaiService.record(loginUserVo.getPegawai(), new Date(), "Supervising Login");
				Map<String, Object> result = new HashMap<>();
				result.put("token", token);
				result.put("id", loginUserVo.getId());
				result.put("idPegawai", loginUserVo.getPegawai().getId());
				result.put("name", loginUserVo.getPegawai().getNamaLengkap());
				return RestUtil.getJsonResponse(result, HttpStatus.OK, mapHeaderMessage);
			} else { // normal login
				Map<String, Object> data = new HashMap<>();
				if (loginUserVo.getPegawai().getJenisPegawai() != null && loginUserVo.getPegawai().getJenisPegawai()
						.getId() == Integer.parseInt(GetSettingDataFixed("KdJenisPegawaiDokter")))
					jadwalDokterService.CheckJadwalDokter(new Date(), loginUserVo.getPegawai());
				mapHeaderMessage.put("X-AUTH-TOKEN", token);
				activityPegawaiService.record(loginUserVo.getPegawai(), new Date(), "Behasil Login Ke System");
				messagePublisher.sendDirectNotification(data);
				Integer idPegawai = 0;
				if (CommonUtil.isNotNullOrEmpty(loginUserVo.getPegawai()))
					idPegawai = loginUserVo.getPegawai().getId();
				loggingSystemAsynchronous.saveSignInLog(0, 0, loginUserVo.getNamaUser(), idPegawai);
				Map<String, Object> result = new HashMap<>();
				result.put("token", token);
				result.put("id", loginUserVo.getId());
				result.put("idPegawai", loginUserVo.getPegawai().getId());
				result.put("name", loginUserVo.getPegawai().getNamaLengkap());
				return RestUtil.getJsonResponse(result, HttpStatus.OK, mapHeaderMessage);
			}
		} catch (Exception ex) {
			LOGGER.error("Signing-in-mobile error {}", ex.getMessage());

			return RestUtil.getJsonHttpStatus(HttpStatus.UNAUTHORIZED);
		}
	}

	@RequestMapping(value = "/sign-out-mobile", method = RequestMethod.POST)
	@ResponseBody
	public ResponseEntity<AuthVO> signOutMobile(@RequestBody AuthVO vo, HttpServletResponse httpResponse) {
		LoginUserVO loginUserVO = loginUserService.findById(vo.getId());

		LOGGER.info("starting sign-out-mobile {}",
				loginUserVO.getNamaUser() + " at " + DateUtil.getIndonesianStringDate(new Date()));

		Integer idPegawai = 0;
		if (CommonUtil.isNotNullOrEmpty(loginUserVO.getPegawai()))
			idPegawai = loginUserVO.getPegawai().getId();
		loggingSystemAsynchronous.saveSignOutLog(loginUserVO.getNamaUser(), idPegawai);
		return RestUtil.getJsonResponse(vo, HttpStatus.OK);
	}

}
