package com.eactive.eai.rms.data.entity.onl.bzwkdstcd;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.data.entity.onl.unifbwk.QUnifBwkTp;
import com.eactive.eai.data.jpa.AbstractDataService;
import com.querydsl.core.types.dsl.BooleanExpression;

import lombok.extern.slf4j.Slf4j;


@Service
@Transactional
@Slf4j
public class UserBusinessService extends
						AbstractDataService<UserBusiness, UserBusinessId, UserBusinessRepository> {

	private UserIdResolver userIdResolver;


	@Autowired
	public UserBusinessService(UserIdResolver userIdResolver) {
		this.userIdResolver = userIdResolver;
	}


	public List<String> getCurrentUserBusinessCodes() {
		return this
								.getCurrentUserBusiness()
								.stream()
								.map(u -> u.getId().getEaiBzwkDstcd())
								.collect(Collectors.toList());
	}


	public List<UserBusiness> getCurrentUserBusiness() {
		return repository.findByIdUserId(userIdResolver.getUserId());
	}


	public List<Map<String, Object>> getRecordAuthList(String empno) {
		QUserBusiness qUserBusiness = QUserBusiness.userBusiness;
		Iterable<UserBusiness> result = repository
								.findAll(qUserBusiness.id.userId.eq(empno));

		return StreamSupport.stream(result.spliterator(), false).map(e -> {
			Map<String, Object> map = new HashMap<>();
			map.put("BZCD", e.getId().getEaiBzwkDstcd());
			return map;
		}).collect(Collectors.toList());
	}


	public Boolean getRecordAuth(String empno, String bzCd) {
		return repository.findById(new UserBusinessId(empno, bzCd)).isPresent();
	}


	public void deleteOrSave(String userId, List<UserBusiness> useBusinesses) {
		List<UserBusiness> existUserBusiness = findByIdUserId(userId,
								useBusinesses);
		existUserBusiness.removeAll(useBusinesses);
		deleteAll(existUserBusiness);
		useBusinesses.forEach(this::saveOrMerge);
	}


	public void deleteAllByUserId(String userId) {
		repository.deleteAll(findByUserId(userId));
	}


	public List<UserBusiness> findByUserId(String userId) {
		QUserBusiness qUserBusiness = QUserBusiness.userBusiness;
		List<UserBusiness> list = new ArrayList<>();
		repository.findAll(qUserBusiness.id.userId.eq(userId))
								.forEach(list::add);
		return list;
	}
	
	public boolean existByUserId(String userId) {
		return repository.exists(QUserBusiness.userBusiness.id.userId.eq(userId));
	}


	private void saveOrMerge(UserBusiness useBusiness) {

		if (!existsById(useBusiness.getId())) {

			try {
				repository.save(useBusiness);
				// 선택한 업무코드 + 그 업무코드로 조회되는 EAI업무구분코드 에 대해서 권한 부여 추가
				// 2020.02.05
				// 기존 insertMergeRM06
				saveWithEaiBzwkDstcd(useBusiness);
			} catch (Exception e) {
				log.warn("업무코드[" + useBusiness.getId().getEaiBzwkDstcd()
										+ "] 중복입니다");
			}

		}

	}


	private void saveWithEaiBzwkDstcd(UserBusiness useBusiness) {
		QUnifBwkTp qUnifBwkTp = QUnifBwkTp.unifBwkTp;

		List<String> eaiBzwkDstcdList = getJPAQueryFactory()
								.select(qUnifBwkTp.eaibzwkdstcd)
								.from(qUnifBwkTp)
								.where(qUnifBwkTp.applcd
														.eq(useBusiness.getId().getEaiBzwkDstcd())
														.and(qUnifBwkTp.eaibzwkdstcd
																				.ne(useBusiness.getId().getEaiBzwkDstcd())))
								.fetch();

		eaiBzwkDstcdList.forEach(eaiBzwkDstcd -> {
			UserBusiness newUserBusiness = new UserBusiness();
			newUserBusiness.setId(new UserBusinessId(
									useBusiness.getId().getUserId(),
									eaiBzwkDstcd));
			newUserBusiness.setSaveType(useBusiness.getSaveType());
			repository.save(newUserBusiness);
		});
	}


	private List<UserBusiness> findByIdUserId(String userId,
							List<UserBusiness> userBusinesses) {
		BooleanExpression predicate = QUserBusiness.userBusiness.id.userId
								.eq(userId);
		List<UserBusiness> list = new ArrayList<>();

		List<String> saveType = userBusinesses
								.stream()
								.map(UserBusiness::getSaveType)
								.filter(StringUtils::isNotBlank)
								.distinct()
								.collect(Collectors.toList());

		if (!saveType.isEmpty()) {
			predicate = predicate.and(QUserBusiness.userBusiness.saveType
									.in(saveType));
		}

		repository.findAll(predicate).forEach(list::add);
		return list;
	}

	public void bizSaveAll(List<UserBusiness> useBusinesses) {
		repository.saveAll(useBusinesses);
	}

	public void deleteBiz(String userId, List<UserBusiness> useBusinesses) {
		List<UserBusiness> existUserBusiness = findByIdUserId(userId, useBusinesses);
		existUserBusiness.removeAll(useBusinesses);
		deleteAll(existUserBusiness);
	}

}
