package com.eactive.eai.rms.onl.manage.authserver.client;

import com.eactive.apim.portal.apispec.entity.ApiSpecInfo;
import com.eactive.apim.portal.apispec.service.ApiSpecInfoService;
import com.eactive.apim.portal.app.entity.Credential;
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.eai.data.entity.onl.message.EAIMessageEntity;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService;
import com.eactive.eai.rms.data.entity.onl.eaimsg.EAIMessageService;
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialManService;
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialService;
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialUI;
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUI;
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUIMapper;
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiSpecInfoUI;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.data.entity.onl.authserver.ClientEntity;
import com.eactive.eai.rms.common.base.OnlBaseService;
import com.eactive.eai.rms.data.entity.onl.authserver.ClientEntityService;
import com.eactive.eai.rms.data.entity.onl.authserver.ClientSearch;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class ClientManService extends OnlBaseService {

	private ClientEntityService clientEntityService;
	private ClientUIMapper clientUIMapper;
	private PortalOrgService portalOrgService;
	private PortalOrgUIMapper portalOrgUIMapper;
	private CredentialManService credentialManService;
	private CredentialService credentialService;
	private EAIMessageService eaiMessageService;
	private ApiSpecInfoService apiSpecInfoService;

	@Autowired
	public ClientManService(ClientEntityService clientEntityService,
							ClientUIMapper clientUIMapper,
							PortalOrgService portalOrgService,
							PortalOrgUIMapper portalOrgUIMapper,
							CredentialManService credentialManService,
							CredentialService credentialService,
							EAIMessageService eaiMessageService,
							ApiSpecInfoService apiSpecInfoService) {
		this.clientEntityService = clientEntityService;
		this.clientUIMapper = clientUIMapper;
		this.portalOrgService = portalOrgService;
		this.portalOrgUIMapper = portalOrgUIMapper;
		this.credentialManService = credentialManService;
		this.credentialService = credentialService;
		this.eaiMessageService = eaiMessageService;
		this.apiSpecInfoService = apiSpecInfoService;
	}


	public Page<ClientUI> selectList(Pageable pageable, ClientSearch clientSearch) {
		Page<ClientEntity> page = clientEntityService.findAll(pageable, clientSearch);
		return page.map(clientUIMapper::toVo);
	}

	public HashMap selectDetailCombo() throws Exception {
		List<PortalOrg> portalOrgList = portalOrgService.findByOrgStatusAndApprovalStatus("ACTIVE", "COMPLETED");
		List<PortalOrgUI> portalOrgUIList = portalOrgList.stream()
				.map(portalOrgUIMapper::toVo)
				.collect(Collectors.toList());
		HashMap map = new HashMap();
		map.put("portalOrgList", portalOrgUIList);
		return map;
	}

	public ClientUI selectDetail(String clientId) {
		ClientEntity clientEntity = clientEntityService.getById(clientId);
		return clientUIMapper.toVo(clientEntity);
	}

	public void insert(ClientUI clientUI) {
		ClientEntity clientEntity = clientUIMapper.toEntity(clientUI);
		clientEntity.setAppstatus("1"); // Set default status to normal
		clientEntityService.save(clientEntity);
	}

	public void update(ClientUI clientUI) {
		ClientEntity clientEntity = clientEntityService.getById(clientUI.getClientId());
		clientUIMapper.updateToEntity(clientUI, clientEntity);
		clientEntityService.save(clientEntity);
	}

	public void delete(String clientId){
		clientEntityService.deleteById(clientId);
	}

	/**
	 * 인증 클라이언트를 차단합니다. (appstatus = '0')
	 * 삭제하지 않고 상태만 차단으로 변경합니다.
	 *
	 * @param clientId 차단할 클라이언트 ID
	 */
	public void blockClient(String clientId) {
		ClientEntity clientEntity = clientEntityService.getById(clientId);
		clientEntity.setAppstatus("0"); // 0: 차단, 1: 정상
		clientEntityService.save(clientEntity);
	}


	public List<String> findAll() {
		List<ClientEntity> clientList = clientEntityService.findAll();
		return clientList.stream()
				.map(ClientEntity::getClientid)
				.collect(Collectors.toList());
	}

	/**
	 * AGW 인증관리(ClientEntity)의 정보를 개발자포탈(Credential)에 반영합니다.
	 * 포탈에 없으면 신규 생성(INSERT), 있으면 업데이트(UPDATE)합니다.
	 *
	 * @param clientId 클라이언트 ID
	 * @return 반영 결과 (INSERTED, UPDATED, SKIPPED_NO_ORG, SKIPPED_INVALID_API, ERROR)
	 */
	public SyncResult syncPortalData(String clientId) {
		try {
			// 1. APIGW 스키마에서 ClientEntity 조회
			ClientEntity clientEntity = clientEntityService.getById(clientId);

			// 2. 유효성 검증 - orgId 확인
			String orgId = clientEntity.getOrgid();
			if (StringUtils.isBlank(orgId)) {
				return SyncResult.builder()
						.success(false)
						.action(SyncResult.SyncAction.SKIPPED_NO_ORG)
						.message("법인(orgId)이 설정되지 않은 클라이언트입니다.")
						.build();
			}

			// 3. API 유효성 검증 (APIGW 스키마)
			List<String> invalidApis = new ArrayList<>();
			List<String> requestedApiIds = new ArrayList<>();

			if (clientEntity.getApiList() != null && !clientEntity.getApiList().isEmpty()) {
				// ClientEntity의 apiList에서 API ID 목록 추출
				requestedApiIds = clientEntity.getApiList().stream()
						.map(EAIMessageEntity::getEaisvcname)
						.collect(Collectors.toList());

				// APIGW에 실제 존재하는 API 조회
				List<EAIMessageEntity> existingApis = eaiMessageService.findByEaisvcnameList(requestedApiIds);
				List<String> existingApiIds = existingApis.stream()
						.map(EAIMessageEntity::getEaisvcname)
						.collect(Collectors.toList());

				// 요청된 API 중 존재하지 않는 API 찾기
				for (String apiId : requestedApiIds) {
					if (!existingApiIds.contains(apiId)) {
						invalidApis.add(apiId);
					}
				}
			}

			// 유효하지 않은 API가 있으면 반영 중단
			if (!invalidApis.isEmpty()) {
				return SyncResult.builder()
						.success(false)
						.action(SyncResult.SyncAction.SKIPPED_INVALID_API)
						.targetApis(requestedApiIds)
						.targetApiCount(requestedApiIds.size())
						.invalidApis(invalidApis)
						.message("존재하지 않는 API가 있어 반영을 중단합니다.")
						.build();
			}

			// 4. MONITORING 스키마로 전환
			DataSourceType monitoringType = DataSourceTypeManager.getDataSourceType("MONITORING");
			DataSourceContextHolder.setDataSourceType(monitoringType);

			// 5. PTL_API_SPEC_INFO에 없는 API 자동 생성
			List<String> createdApiSpecs = new ArrayList<>();
			if (clientEntity.getApiList() != null && !clientEntity.getApiList().isEmpty()) {
				for (EAIMessageEntity apiEntity : clientEntity.getApiList()) {
					String apiId = apiEntity.getEaisvcname();
					if (!apiSpecInfoService.findById(apiId).isPresent()) {
						// PTL_API_SPEC_INFO에 없으면 자동 생성
						ApiSpecInfo newApiSpec = new ApiSpecInfo();
						newApiSpec.setApiId(apiId);
						newApiSpec.setApiName(StringUtils.isNotBlank(apiEntity.getEaisvcdesc())
								? apiEntity.getEaisvcdesc() : apiId);
						newApiSpec.setApiSimpleDescription(apiEntity.getEaisvcdesc());
						newApiSpec.setDisplayYn("Y"); // 기본값: 공개
						apiSpecInfoService.create(newApiSpec);
						createdApiSpecs.add(apiId);
					}
				}
			}

			// 6. 기존 Credential 확인
			Credential existingCredential = credentialService.findByClientidAndOrgid(clientId, orgId);

			// 7. 데이터 변환 (ClientEntity → CredentialUI)
			CredentialUI credentialUI = convertToCredentialUI(clientEntity);

			SyncResult.SyncAction action;
			if (existingCredential != null) {
				// 업데이트: 기존 값 유지해야 할 필드 처리
				Credential existing = existingCredential;
				if (StringUtils.isNotBlank(existing.getAppDescription())) {
					credentialUI.setAppDescription(existing.getAppDescription());
				}
				if (StringUtils.isNotBlank(existing.getAppIconFileId())) {
					credentialUI.setAppIconFileId(existing.getAppIconFileId());
				}
				if (StringUtils.isNotBlank(existing.getServer())) {
					credentialUI.setServer(existing.getServer());
				}

				// 8. 포탈 스키마에 업데이트
				credentialManService.update(credentialUI);
				action = SyncResult.SyncAction.UPDATED;
			} else {
				// 신규 생성: 기본값 설정
				if (StringUtils.isBlank(credentialUI.getAppDescription())) {
					credentialUI.setAppDescription("APIGW에서 반영된 인증정보");
				}

				// 8. 포탈 스키마에 신규 생성
				credentialManService.insert(credentialUI);
				action = SyncResult.SyncAction.INSERTED;
			}

			return SyncResult.builder()
					.success(true)
					.action(action)
					.message("포탈 정보 반영 완료")
					.targetApis(requestedApiIds)
					.targetApiCount(requestedApiIds.size())
					.syncedApis(requestedApiIds)
					.syncedApiCount(requestedApiIds.size())
					.createdApiSpecs(createdApiSpecs)
					.createdApiSpecCount(createdApiSpecs.size())
					.build();

		} catch (Exception e) {
			logger.error("포탈 정보 반영 중 오류 발생", e);
			return SyncResult.builder()
					.success(false)
					.action(SyncResult.SyncAction.ERROR)
					.message("반영 중 오류: " + e.getMessage())
					.build();
		}
	}

	/**
	 * ClientEntity를 CredentialUI로 변환합니다.
	 *
	 * @param clientEntity APIGW 클라이언트 엔티티
	 * @return CredentialUI 포탈 인증정보 UI 객체
	 */
	private CredentialUI convertToCredentialUI(ClientEntity clientEntity) {
		CredentialUI credentialUI = new CredentialUI();

		// 기본 인증정보
		credentialUI.setClientid(clientEntity.getClientid());
		credentialUI.setClientname(clientEntity.getClientname());
		credentialUI.setClientsecret(clientEntity.getClientsecret());

		// OAuth 설정
		credentialUI.setScope(clientEntity.getScope());
		credentialUI.setGranttypes(clientEntity.getGranttypes());
		credentialUI.setAccesstokenvalidityseconds(clientEntity.getAccesstokenvalidityseconds());
		credentialUI.setRefreshtokenvalidityseconds(clientEntity.getRefreshtokenvalidityseconds());

		// 보안 설정
		credentialUI.setAllowedips(clientEntity.getAllowedips());
		credentialUI.setAuthorities(clientEntity.getAuthorities());
		credentialUI.setRedirecturi(clientEntity.getRedirecturi());
		credentialUI.setSecuritykey(clientEntity.getSecuritykey());
		credentialUI.setAutoapprove(clientEntity.getAutoapprove());
		credentialUI.setResourceids(clientEntity.getResourceids());

		// 조직 정보
		credentialUI.setOrgid(clientEntity.getOrgid());
		credentialUI.setOrgname(clientEntity.getOrgname());

		// 앱 상태
		credentialUI.setAppstatus(clientEntity.getAppstatus());
		credentialUI.setDailytokenlimit(clientEntity.getDailytokenlimit());

		// 수정 정보
		credentialUI.setModifiedby(clientEntity.getModifiedby());
		if (clientEntity.getModifiedon() != null) {
			credentialUI.setModifiedon(clientEntity.getModifiedon().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
		}

		// API 목록 변환
		List<ApiSpecInfoUI> apiList = new ArrayList<>();
		if (clientEntity.getApiList() != null) {
			for (EAIMessageEntity apiEntity : clientEntity.getApiList()) {
				ApiSpecInfoUI apiUI = new ApiSpecInfoUI();
				apiUI.setApiId(apiEntity.getEaisvcname());
				apiList.add(apiUI);
			}
		}
		credentialUI.setApiList(apiList);

		return credentialUI;
	}
}
