package com.eactive.eai.rms.data.entity.man.user;

import com.eactive.apim.portal.user.entity.QUserInfo;
import com.eactive.apim.portal.user.entity.UserInfo;
import com.eactive.eai.rms.common.acl.user.ui.UserUISearch;
import com.eactive.eai.rms.data.entity.man.role.QRole;
import com.eactive.eai.rms.data.jpa.AbstractEMSDataSerivce;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.BooleanExpression;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.QueryHints;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional(transactionManager = "transactionManagerForEMS")
public class UserInfoService extends
		AbstractEMSDataSerivce<UserInfo, String, UserInfoRepository> {

	public List<UserInfo> selectUserById(String userId) {
		QUserInfo qUserInfo = QUserInfo.userInfo;

		return getJPAQueryFactory()
				.selectFrom(qUserInfo)
				.where(qUserInfo.userid.eq(userId))
				.fetch();
	}

	public Optional<UserInfo> findByOfctelno(String ofctelno) {
		BooleanExpression predicate = QUserInfo.userInfo.ofctelno.eq(ofctelno);
		return repository.findOne(predicate);
	}

	public boolean isEAITeam(String empno, List<String> roleId) {
		QUserInfo qUserInfo = QUserInfo.userInfo;
		QRole qRole = QRole.role;

		List<UserInfo> result = getJPAQueryFactory()
				.selectFrom(qUserInfo)
				.join(qRole)
				.on(qUserInfo.roleidnfiname.eq(qRole.roleId))
				.where(qUserInfo.userid.eq(empno)
						.and(qRole.roleId.in(roleId)))
				.limit(1)
				.fetch();

		return !result.isEmpty();
	}

	public Page<UserInfo> findAll(Pageable pageable,
								  UserUISearch userUiSearch) {
		QUserInfo qUserInfo = QUserInfo.userInfo;
		QUserRole qUserRole = QUserRole.userRole;

		BooleanBuilder predicate = new BooleanBuilder();

		if (StringUtils.isNotBlank(userUiSearch.getSearchUserId())) {
			predicate.and(qUserInfo.userid.containsIgnoreCase(userUiSearch.getSearchUserId()));
		}

		if (StringUtils.isNotBlank(userUiSearch.getSearchUserName())) {
			predicate.and(qUserInfo.username.containsIgnoreCase(userUiSearch.getSearchUserName()));
		}

		if (StringUtils.isNotBlank(userUiSearch.getSearchRoleName())) {
			List<String> userId = getJPAQueryFactory()
					.selectDistinct(qUserRole.id.userId)
					.from(qUserRole)
					.where(qUserRole.id.roleId.contains(userUiSearch.getSearchRoleName()))
					.setHint(QueryHints.CACHEABLE, true)
					.fetch();

            predicate.and(qUserInfo.userid.in(userId));
        }

		return repository.findAll(predicate, pageable);
	}

	public List<Map<String, Object>> selectAdminRoleUser(String roleId) {
		QUserInfo qUserInfo = QUserInfo.userInfo;
		QUserRole qUserRole = QUserRole.userRole;

		List<Tuple> results = getJPAQueryFactory()
				.select(qUserInfo.userid, qUserRole.id.roleId)
				.from(qUserInfo)
				.join(qUserRole)
				.on(qUserInfo.userid.eq(qUserRole.id.userId))
				.where(qUserRole.id.roleId.eq(roleId))
				.setHint(QueryHints.CACHEABLE, true)
				.fetch();

		return results.stream().map(tuple -> {
			Map<String, Object> userRoleMap = new HashMap<>();
			userRoleMap.put("USERID", tuple.get(qUserInfo.userid));
			userRoleMap.put("ROLEID", tuple.get(qUserRole.id.roleId));
			return userRoleMap;

		}).collect(Collectors.toList());
	}

	public List<UserInfo> findAllByRoleId(String roleId) {
		QUserInfo qUserInfo = QUserInfo.userInfo;
		QUserRole qUserRole = QUserRole.userRole;

		return getJPAQueryFactory()
				.selectFrom(qUserInfo)
				.join(qUserRole).on(qUserInfo.userid.eq(qUserRole.id.userId))
				.where(qUserRole.id.roleId.eq(roleId))
				.fetch();
	}

	public Page<UserInfo> findByUsername(Pageable pageable, String username) {
		QUserInfo qUserInfo = QUserInfo.userInfo;
		BooleanExpression predicate = qUserInfo.isNotNull();

		if(StringUtils.isNotBlank(username)) {
			predicate = QUserInfo.userInfo.username.containsIgnoreCase(username);
		}

		return repository.findAll(predicate, pageable);
	}

	/**
	 * 대소문자 구분 없이 사용자 ID로 검색
	 * @param userId 사용자 ID
	 * @return 사용자 정보 (Optional)
	 */
	public Optional<UserInfo> findByUserIdIgnoreCase(String userId) {
		QUserInfo qUserInfo = QUserInfo.userInfo;

		UserInfo result = getJPAQueryFactory()
				.selectFrom(qUserInfo)
				.where(qUserInfo.userid.equalsIgnoreCase(userId))
				.fetchOne();

		return Optional.ofNullable(result);
	}

}