package com.eactive.eai.rms.data.entity.onl.apim.apigroup;

import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroup;
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroupApi;
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroupApiId;
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroup;
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroupApi;
import com.eactive.eai.data.jpa.AbstractDataService;
import com.eactive.eai.rms.onl.apim.apigroup.ui.ApiGroupUISearch;
import com.querydsl.core.types.dsl.BooleanExpression;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Transactional
public class ApiGroupService extends AbstractDataService<ApiGroup, String, ApiGroupRepository> {

	public Page<ApiGroup> selectList(ApiGroupUISearch apiGroupUISearch, Pageable pageable) {
		QApiGroup qApiGroup = QApiGroup.apiGroup;
		BooleanExpression predicate = qApiGroup.groupName.containsIgnoreCase(apiGroupUISearch.getSearchGroupName());
		
		if (StringUtils.isNotBlank(apiGroupUISearch.getSearchGroupDesc())) {
			predicate = predicate.and(qApiGroup.groupDesc.containsIgnoreCase(apiGroupUISearch.getSearchGroupDesc()));
		}

		if (StringUtils.isNotBlank(apiGroupUISearch.getSearchDisplayYn())) {
			predicate = predicate.and(qApiGroup.displayYn.eq(apiGroupUISearch.getSearchDisplayYn()));
		}
		return repository.findAll(predicate, pageable);
	}

	public Optional<ApiGroup> findByIdWithApiList(String id) {
		return repository.findById(id)
			.map(apiGroup -> {
				Hibernate.initialize(apiGroup.getApiGroupApiList());
				return apiGroup;
			});
	}

	public void deleteApiGroupApiByApiId(String apiId) {
		List<ApiGroup> apiGroups = repository.findAll();
		for (ApiGroup apiGroup : apiGroups) {
			List<ApiGroupApi> apiGroupApis = apiGroup.getApiGroupApiList();
			apiGroupApis.removeIf(apiGroupApi -> apiGroupApi.getId().getApiId().equals(apiId));
			repository.save(apiGroup);
		}
	}

	public List<ApiGroup> findByApiId(String apiId) {
		QApiGroup qApiGroup = QApiGroup.apiGroup;
		QApiGroupApi qApiGroupApi = QApiGroupApi.apiGroupApi;

		// Oracle에서 CLOB 필드(contentDetail 등)가 있으면 DISTINCT를 사용할 수 없으므로
		// api_group_api 테이블에서 api_group_id만 조회한 후 엔티티를 조회
		List<String> apiGroupIds = getJPAQueryFactory()
				.select(qApiGroupApi.id.apiGroupId)
				.from(qApiGroupApi)
				.where(qApiGroupApi.id.apiId.eq(apiId))
				.fetch();

		if (apiGroupIds.isEmpty()) {
			return new ArrayList<>();
		}

		return getJPAQueryFactory().selectFrom(qApiGroup)
				.where(qApiGroup.id.in(apiGroupIds))
				.fetch();
	}

	/** API 를 지정한 그룹 목록에만 소속시킨다(기존 소속 제거 후 재설정). */
	public void setApiGroupsForApi(String apiId, List<String> groupIds) {
		deleteApiGroupApiByApiId(apiId);
		if (groupIds == null) {
			return;
		}
		for (String gid : groupIds) {
			if (StringUtils.isBlank(gid)) {
				continue;
			}
			ApiGroup group = repository.findById(gid).orElse(null);
			if (group == null) {
				continue;
			}
			Hibernate.initialize(group.getApiGroupApiList());
			List<ApiGroupApi> list = group.getApiGroupApiList();
			boolean exists = false;
			for (ApiGroupApi a : list) {
				if (a.getId() != null && apiId.equals(a.getId().getApiId())) {
					exists = true;
					break;
				}
			}
			if (!exists) {
				ApiGroupApi a = new ApiGroupApi();
				a.setId(new ApiGroupApiId(gid, apiId));
				a.setDisplayOrder(list.size() + 1);
				list.add(a);
				repository.save(group);
			}
		}
	}
}
