package com.eactive.eai.rms.common.acl.user;

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

import com.eactive.eai.rms.common.acl.user.mapper.UserAthrRoleChgHistoryUIMapper;
import com.eactive.eai.rms.common.acl.user.mapper.UserLoginHistoryUIMapper;
import com.eactive.eai.rms.common.acl.user.mapper.UserUIMapper;
import com.eactive.eai.rms.common.acl.user.ui.*;
import com.eactive.eai.rms.data.entity.man.user.*;
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusiness;
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessId;
import com.eactive.eai.rms.data.entity.onl.code.CodeService;
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.apim.portal.user.entity.UserInfo;
import com.eactive.eai.common.seed.Seed;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.spring.LocaleMessage;
import com.eactive.eai.rms.common.util.CommonConstants;
import com.eactive.eai.rms.data.entity.man.role.Role;
import com.eactive.eai.rms.data.entity.man.role.RoleService;
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
import com.eactive.eai.rms.onl.common.exception.BizException;
import com.eactive.ext.djb.DamoManager;

import lombok.RequiredArgsConstructor;

@Service
@Transactional(transactionManager = "transactionManagerForEMS")
@RequiredArgsConstructor
public class UserManService extends BaseService {
	
	

	private final UserInfoService userInfoService;
	private final UserRoleService userRoleService;
	private final UserBusinessService userBusinessService;
	private final LocaleMessage localeMessage;
	private final RoleService roleService;
	private final UserServiceTypeService userServiceTypeService;
	private final UserUIMapper userUIMapper;
	private final MonitoringContext monitoringContext;
	private final UserAthrRoleChgHistoryService userAthrRoleChgHistoryService;
	private final UserAthrRoleChgHistoryUIMapper userAthrRoleChgHistoryUIMapper;
	private final UserLoginHistoryService userLoginHistoryService;
	private final UserLoginHistoryUIMapper userLoginHistoryUIMapper;
	private final CodeService codeService;

	public Page<UserUI> selectList(Pageable pageable, UserUISearch userUiSearch) {
		/* 사용자명 마스킹처리요청 _ 2024.12.10 */
		Page<UserInfo>  userInfos = userInfoService.findAll(pageable, userUiSearch);

		List<UserUI> content = userInfos.getContent().stream()
				.map(entity -> {
					UserUI userInfo = userUIMapper.toVo(entity);
					userInfo.setUserName(MaskingUtils.maskName(entity.getUsername()));
					return userInfo;
				}).collect(Collectors.toList());

		return new PageImpl<>(content, pageable, userInfos.getTotalElements());
	}

	public List<Map<String, Object>> selectRole(String searchUseYn) {
		return roleService.selectRole(searchUseYn);
	}

	public UserUI selectDetail(String userId) {
		UserInfo userInfo = userInfoService.getById(userId);
		UserUI userUI = userUIMapper.toVo(userInfo);

		String roleidnfiname = selectUserRoleList(userId)
				.stream()
				.filter(role -> "true".equals(role.getChk()))
				.map(UserRoleUI::getRoleId)
				.collect(Collectors.joining(","));

		userUI.setRoleidnfiname(roleidnfiname);
		return userUI;
	}

	public void insert(UserUI userUI, AdminLoginVo adminLoginVo) {

		// 중복체크
		if (userInfoService.existsById(userUI.getUserId())) {
			throw new BizException(localeMessage
					.getString("user.userIdExists"));
		}

		UserInfo userInfo = userUIMapper.toEntity(userUI);
		userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
		
		String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");

		try {
			userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()+subfix));
		} catch (Exception e) {
			throw new RuntimeException("Error encrypting password", e);
		}

		userInfoService.save(userInfo);
		String roleId = monitoringContext.getStringProperty(
				MonitoringContext.USER_DEFAULT_RULE, "newbie");
		UserRole userRole = new UserRole();
		userRole.setId(new UserRoleId(userUI.getUserId(), roleId));
		userRoleService.save(userRole);

		DataSourceTypeManager.getDynamicDataSourceTypes().stream()
				.map(DataSourceType::getName)
				.forEach(type -> userServiceTypeService
						.insertUserServiceType(userUI
										.getUserId(),
								type));
		insertUserAthrRoleChgHistory(userUI.getUserId(), CommonConstants.CHANGE_TYPE_ROLE, roleId,
				adminLoginVo.getLoginId(), adminLoginVo.getLoginIp());

		insertUserAthrRoleChgHistory(userUI.getUserId(), CommonConstants.CHANGE_TYPE_ATHR,
				CommonConstants.USER_SERVICE_TYPE_APIGW, adminLoginVo.getLoginId(), adminLoginVo.getLoginIp());

	}

	public void update(UserUI userUI) {
		UserInfo userInfo = userInfoService.getById(userUI.getUserId());
		userUIMapper.updateToEntity(userUI, userInfo);
		userInfoService.save(userInfo);
	}

	public void delete(String userId) {
		userBusinessService.deleteAllByUserId(userId);
		userServiceTypeService.deleteAllByUserId(userId);
		userRoleService.deleteAllByUserId(userId);
		userInfoService.deleteById(userId);
	}

	public void updatePassword(UserUI userUI) throws Exception {
		String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
		UserInfo userInfo = userInfoService.getById(userUI.getUserId());
		userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()+subfix));
		userUIMapper.updateToEntity(userUI, userInfo);
		userInfoService.save(userInfo);
	}

	public List<UserRoleUI> selectUserRoleList(String userId) {
		Iterable<Role> roles = roleService.findAllRolesByUseYn("Y");
		List<UserRoleUI> userRoleUIs = new ArrayList<>();

		roles.forEach(role -> {
			Optional<UserRole> userRole = userRoleService.findById(
					new UserRoleId(userId, role.getRoleId()));

			UserRoleUI userRoleUI = new UserRoleUI();
			userRoleUI.setRoleId(role.getRoleId());
			userRoleUI.setRoleName(role.getRoleName());
			userRoleUI.setRoleDesc(role.getRoleDesc());
			userRoleUI.setChk(userRole.isPresent() ? "true" : "false");

			userRoleUIs.add(userRoleUI);
		});

		return userRoleUIs;
	}

	public void transactionUserRoleAndCheckAdmin(String userId, List<UserRoleUI> userList, AdminLoginVo adminLoginVo) {
		List<UserRole> userRoles = userList.stream()
				.map(userRoleUI -> {
					UserRole userRole = new UserRole();
					userRole.setId(new UserRoleId(userId,
							userRoleUI.getRoleId()));
					return userRole;
				}).collect(Collectors.toList());

		userRoleService.deleteOrSave(userId, userRoles);

		String joinedUserRoles = userList.stream()
				.map(UserRoleUI::getRoleId)
				.collect(Collectors.joining(","));

		updateUserInfoRoles(userId, joinedUserRoles);

		// 이력 추가
		insertUserAthrRoleChgHistory(userId, CommonConstants.CHANGE_TYPE_ROLE, joinedUserRoles,
				adminLoginVo.getLoginId(), adminLoginVo.getLoginIp());

		boolean hasAdminRole = userList.stream()
				.anyMatch(role -> "admin".equalsIgnoreCase(role.getRoleId()));

		if(hasAdminRole) {
			updateUserBusinessForAdmin(userId);
		}
	}

	private void updateUserInfoRoles(String userId, String joinedUserRoles){
		UserInfo userInfo = userInfoService.getById(userId);
		userInfo.setRoleidnfiname(joinedUserRoles);
		userInfoService.save(userInfo);
	}

	private void updateUserBusinessForAdmin(String userId) {
		List<UserBusiness> allUserBusinesses = userBusinessService.findAll();
		List<UserBusiness> newUserBusinesses = allUserBusinesses.stream()
				.map(biz -> {
					UserBusiness newUserBusiness = new UserBusiness();
					newUserBusiness.setId(new UserBusinessId(userId, biz.getId().getEaiBzwkDstcd()));
					newUserBusiness.setSaveType(biz.getSaveType());
					return newUserBusiness;
				}).collect(Collectors.toList());

		userBusinessService.deleteOrSave(userId, newUserBusinesses);
	}

	public List<Map<String, Object>> selectAdminRoleUser(String roleId) {
		return userInfoService.selectAdminRoleUser(roleId);
	}

	public Page<UserUI> findUserList(Pageable pageable, String username) {
		return userInfoService.findByUsername(pageable, username).map(userUIMapper::toVo);
	}

	public void insertUserAthrRoleChgHistory(String userId, String changeType, String changeDetail,
											 String adminId, String ip) {

		UserAthrRoleChgHistory userAthrRoleChgHistory = new UserAthrRoleChgHistory();

		userAthrRoleChgHistory.setUserId(userId);
		userAthrRoleChgHistory.setChgGb(changeType);	// ATHR : 권한, ROLE : 역할
		userAthrRoleChgHistory.setChgDtl(changeDetail);
		userAthrRoleChgHistory.setAmdrId(adminId);
		userAthrRoleChgHistory.setCctnIp(ip);

		userAthrRoleChgHistoryService.save(userAthrRoleChgHistory);
	}

	public Page<UserAthrRoleChgHistoryUI> selectUserChgHistoryList(Pageable pageable, String userId) {
		Page<UserAthrRoleChgHistory> page = userAthrRoleChgHistoryService.findAll(pageable, userId);
		Page<UserAthrRoleChgHistoryUI> ui = page.map(userAthrRoleChgHistoryUIMapper::toVo);

		ui.forEach(e-> {
			String codeName = codeService.findCodeName("USER_ATHR_ROLE_CHANGE_TYPE", e.getChgGb()).orElse("");
			e.setChgGbName(codeName);
		});

		return ui;
	}

	public Page<UserLoginHistoryUI> selectList(Pageable pageable, UserLoginHistoryUI userLoginHistoryUI) {
		Page<UserLoginHistory> page = userLoginHistoryService.findAll(pageable, userLoginHistoryUI);
		Page<UserLoginHistoryUI> ui = page.map(userLoginHistoryUIMapper::toVo);

		ui.forEach(e -> {
			if(userInfoService.existsById(e.getUserId())) {
				UserInfo userInfo = userInfoService.getById(e.getUserId());
				e.setUsername(userInfo.getUsername());
				e.setRoleidnfiname(userInfo.getRoleidnfiname());
			}
		});

		return ui;
	}
	
}
