package com.eactive.eai.rms.onl.apim.portaluser;

import com.eactive.apim.portal.file.entity.FileDetail;
import com.eactive.apim.portal.file.entity.FileInfo;
import com.eactive.apim.portal.file.service.FileService;
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
import com.eactive.apim.portal.portaluser.entity.PortalUserPrivacyAgreement;
import com.eactive.eai.common.util.SystemUtil;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.common.spring.LocaleMessage;
import com.eactive.eai.rms.data.entity.onl.apim.approval.ApprovalService;
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryService;
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService;
import com.eactive.eai.rms.data.entity.onl.apim.portaluser.PortalUserService;
import com.eactive.eai.rms.data.entity.onl.apim.portaluser.PortalUserUISearch;
import com.eactive.eai.rms.data.entity.onl.apim.portaluserterms.PortalUserTermsService;
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgManService;
import com.eactive.eai.rms.onl.common.exception.BizException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

	/** PortalProperty 그룹명 */
	private static final String PORTAL_PROPERTY_GROUP = "Portal";
	/** 사용자 별 휴대폰 번호 중복 허용 프로퍼티 키 (true:허용, false:허용안함, 기본 false) */
	private static final String PROP_MOBILE_DUPLICATE_ALLOW = "user.mobile.duplicate.allow";
	/** 가입자 완전삭제(hard delete) 허용 프로퍼티 키 (true:허용, 기본 false) */
	private static final String HARD_DELETE_FLAG_KEY = "user.hard-delete.enabled";

	private final PortalUserService portalUserService;
	private final PortalUserUIMapper portalUserUIMapper;
	private final LocaleMessage localeMessage;
	private final PortalOrgService portalOrgService;
	private final FileService fileService;
	private final PortalOrgManService portalOrgManService;
//	private final PasswordEncoder passwordEncoder;
	private final PasswordEncoder kjbSafedbPasswordEncoder;
	private final PortalUserTermsService portalUserTermsService;
	private final ApprovalService approvalService;
	private final PortalInquiryService portalInquiryService;
	private final PortalPropertyService portalPropertyService;

	/** 가입자 목록 '선택 삭제'(완전삭제) 버튼 노출 여부 */
	public boolean isHardDeleteEnabled() {
		Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
		return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
	}

	public Page<PortalUserUI> selectList(Pageable pageable, PortalUserUISearch portalUserUISearch) {
		Page<PortalUser> portalUser = portalUserService.findAll(pageable, portalUserUISearch);
		return portalUser.map(entity -> {
			PortalUserUI ui = convertToUIWithMaskOption(entity, false);

			// 목록의 개인정보(사용자명/이메일아이디/휴대폰번호)는 항상 마스킹하여 노출 (상세 조회에서만 마스킹 해제)
			if (ui != null) {
				if (StringUtils.isNotBlank(ui.getUserName())) {
					ui.setUserName(MaskingUtils.maskName(ui.getUserName()));
				}
				if (StringUtils.isNotBlank(ui.getLoginId())) {
					ui.setLoginId(MaskingUtils.maskEmailId(ui.getLoginId()));
				}
				if (StringUtils.isNotBlank(ui.getMobileNumber())) {
					ui.setMobileNumber(MaskingUtils.maskPhoneNumber(ui.getMobileNumber()));
				}
			}

			if (entity.getPortalOrg() != null) {
				setPortalOrgUI(entity, ui);
			}
			return ui;
		});
	}

	/**
	 * 사용자 별 휴대폰 번호 중복 허용 프로퍼티(Portal/user.mobile.duplicate.allow)를 확인한다.
	 * 프로퍼티가 없으면 기본값 'false'(허용안함)으로 생성하며, '허용안함'일 때 중복 휴대폰번호 사용자 수를 함께 반환한다.
	 *
	 * @return enabled(boolean): 중복 조회 기능 활성 여부, count(long): 중복 휴대폰번호 사용자 수
	 */
	public Map<String, Object> getMobileDuplicateInfo() {
		String allowValue = portalPropertyService.getOrCreateProperty(
				PORTAL_PROPERTY_GROUP,
				PROP_MOBILE_DUPLICATE_ALLOW,
				"false",
				"사용자 별 휴대폰 번호 중복 허용 여부 (true:허용, false:허용안함). 허용안함일 때 사용자 관리 목록에 중복 휴대폰번호 사용자 조회 기능을 노출");

		// 레거시 Y/N 값도 허용으로 함께 인식 (true/Y → 허용, 그 외 → 허용안함)
		boolean allowed = "true".equalsIgnoreCase(allowValue) || "Y".equalsIgnoreCase(allowValue);
		boolean checkEnabled = !allowed;
		long duplicateUserCount = checkEnabled ? portalUserService.countDuplicateMobileUsers() : 0L;

		Map<String, Object> info = new HashMap<>();
		info.put("enabled", checkEnabled);
		info.put("count", duplicateUserCount);
		return info;
	}

	public PortalUserUI selectDetail(String id, boolean isMasked) {
		PortalUser portalUser = portalUserService.getById(id);
		PortalUserUI portalUserUI = convertToUIWithMaskOption(portalUser, isMasked);

		if (portalUser.getPortalOrg() != null) {
			setPortalOrgUI(portalUser, portalUserUI);
		}
		return portalUserUI;
	}

	public PortalUserUI selectDetailUnmask(String id) {
		return selectDetail(id, false);
	}

	private void setPortalOrgUI(PortalUser portalUser, PortalUserUI portalUserUI) {
		portalOrgManService.getPortalOrgUI(portalUser.getPortalOrg().getId())
				.ifPresent(orgUI -> {
					// IP 마스킹 처리 추가
					if (StringUtils.isNotBlank(orgUI.getIpWhitelist())) {
						orgUI.setIpWhitelist(MaskingUtils.maskIpAddress(orgUI.getIpWhitelist()));
					}

					portalUserUI.setPortalOrgUIs(orgUI);
					if (StringUtils.isNotBlank(portalUser.getPortalOrg().getCompRegFile())) {
						try {
							FileInfo fileInfo = fileService.findById(portalUser.getPortalOrg().getCompRegFile());
							orgUI.setFileInfo(fileInfo);
							FileDetail fileDetail = fileInfo.getFileDetails().get(0);
							orgUI.setFileName(fileDetail.getOriginalFileName() + "." + fileDetail.getFileExtension());
						} catch (Exception e) {
							// 파일 정보가 DB에 없는 경우 무시하고 계속 진행
							log.warn("File not found for compRegFile: {}", portalUser.getPortalOrg().getCompRegFile());
						}
					}
				});
	}
	/**
	 * PortalUser 엔티티를 UI 객체로 변환하고, 필요한 경우 마스킹 처리를 수행합니다.
	 *
	 * @param portalUser 변환할 PortalUser 엔티티
	 * @param isMasked true 인 경우 개인정보(이름, 이메일, 로그인 ID, 휴대폰번호)를 마스킹 처리
	 * @return 변환된 PortalUserUI 객체 (마스킹 처리 여부에 따라 처리됨)
	 */
	private PortalUserUI convertToUIWithMaskOption(PortalUser portalUser, boolean isMasked) {
		PortalUserUI ui = portalUserUIMapper.toVo(portalUser);

		if (ui != null && isMasked) {
			if (StringUtils.isNotBlank(ui.getUserName())) {
				ui.setUserName(MaskingUtils.maskName(ui.getUserName()));
			}
			if (StringUtils.isNotBlank(ui.getEmailAddr())) {
				ui.setEmailAddr(MaskingUtils.maskEmailId(ui.getEmailAddr()));
			}
			if (StringUtils.isNotBlank(ui.getLoginId())) {
				ui.setLoginId(MaskingUtils.maskEmailId(ui.getLoginId()));
			}
			if (StringUtils.isNotBlank(ui.getMobileNumber())) {
				ui.setMobileNumber(MaskingUtils.maskPhoneNumber(ui.getMobileNumber()));
			}
		}

		return ui;
	}

	public void insert(PortalUserUI portalUserUI) throws Exception {
		// 중복체크
		if (portalUserService.existsByLoginId(portalUserUI.getLoginId())) {
			throw new BizException(localeMessage.getString("portalUser.checkUserMsg1"));
		}

		PortalUser portalUser = portalUserUIMapper.toEntity(portalUserUI);
		portalUser.setPasswordHash(kjbSafedbPasswordEncoder.encode("!" + portalUserUI.getLoginId()));
		portalUser.setLoginFailureCount(0);
		portalUser.setAccountLockYn("N");
		portalUser.setEmailAddr(portalUserUI.getLoginId());
		portalUser.setId(null);

		// 기본 상태 설정
		if (portalUser.getUserStatus() == null) {
			portalUser.setUserStatus(PortalUserEnums.UserStatus.ACTIVE);
		}
		if (portalUser.getApprovalStatus() == null) {
			portalUser.setApprovalStatus(PortalUserEnums.ApprovalStatus.COMPLETED);
		}

		if (StringUtils.isNotBlank(portalUserUI.getOrgId())) {
			portalUser.setPortalOrg(portalOrgService.getById(portalUserUI.getOrgId()));
		}
		portalUserService.save(portalUser);
	}

	public void update(PortalUserUI portalUserUI) {
		PortalUser portalUser = portalUserService.getById(portalUserUI.getId());
		portalUserUIMapper.updateToEntity(portalUserUI, portalUser);

		if (StringUtils.isNotBlank(portalUserUI.getOrgId())) {
			PortalOrg portalOrg = portalOrgService.getById(portalUserUI.getOrgId());
			portalUser.setPortalOrg(portalOrg);
		} else {
			// 개인사용자이면서 법인을 "없음"으로 선택한 경우 ORG_ID 삭제
			if (portalUserUI.getRoleCode() == PortalUserEnums.RoleCode.ROLE_USER) {
				portalUser.setPortalOrg(null);
			}
		}

		portalUserService.save(portalUser);
	}

	public void removeUser(String id) {
		PortalUser portalUser = portalUserService.getById(id);

		// 이용약관 동의 이력 삭제
		List<PortalUserPrivacyAgreement> agreements = portalUserTermsService.findAllByCreatedBy(portalUser.getId());
		if (!agreements.isEmpty()) {
			portalUserTermsService.deleteAll(agreements);
		}

		String withdrawalDate = "-d" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));

		portalUser.setLoginId(portalUser.getId()  + withdrawalDate);
		portalUser.setEmailAddr(portalUser.getId() + withdrawalDate);
		portalUser.setUserName("삭제된사용자");
		portalUser.setMobileNumber("");

		portalUser.setUserStatus(PortalUserEnums.UserStatus.REMOVED);

		portalUserService.save(portalUser);
	}

	public boolean checkDuplicateId(String loginId) {
		return !portalUserService.existsByLoginId(loginId);
	}

	public void hardDeleteUser(String id) {
		if (SystemUtil.isProdServer()) {
			throw new BizException("운영 환경에서는 완전삭제를 수행할 수 없습니다.");
		}
		PortalUser portalUser = portalUserService.getById(id);
		if (portalUser.getUserStatus() != PortalUserEnums.UserStatus.REMOVED) {
			throw new BizException("삭제(탈퇴) 상태인 사용자만 완전삭제할 수 있습니다.");
		}

		List<String> dependencies = new ArrayList<>();
		long messageCount = portalUserService.countMessageRequestByUserId(id);
		if (messageCount > 0) dependencies.add("메시지 " + messageCount + "건");

		if (!dependencies.isEmpty()) {
			throw new BizException("의존 데이터가 존재하여 완전삭제할 수 없습니다: " + String.join(", ", dependencies));
		}

		portalUserService.deleteById(id);
	}

	public void passwordReset(String id) {
		PortalUser portalUser = portalUserService.getById(id);

		// 패스워드를 초기 패스워드("!" + loginId)로 초기화
		portalUser.setPasswordHash(kjbSafedbPasswordEncoder.encode("!" + portalUser.getLoginId()));

		// 로그인 실패 횟수 초기화
		portalUser.setLoginFailureCount(0);

		// 계정 잠금 해제
		portalUser.setAccountLockYn("N");

		portalUserService.save(portalUser);

		log.info("Password reset for user: {}", portalUser.getLoginId());
	}

}
