package com.eactive.eai.rms.data.entity.onl.eaimsg;

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

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
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.eai.data.entity.onl.adapter.QAdapter;
import com.eactive.eai.data.entity.onl.authserver.QScopeEntity;
import com.eactive.eai.data.entity.onl.logger.QStatLog;
import com.eactive.eai.data.entity.onl.message.EAIMessageEntity;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.data.entity.onl.message.QServiceMessageEntity;
import com.eactive.eai.data.entity.onl.routing.QRouting;
import com.eactive.eai.data.entity.onl.stdmessage.QStandardMessageInfo;
import com.eactive.eai.data.jpa.AbstractDataService;
import com.eactive.eai.rms.data.entity.onl.djb.apistatus.QApiStatus;
import com.eactive.eai.rms.data.entity.onl.authserver.QScopeInfo;
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQuery;

@Service
@Transactional
@RequiredArgsConstructor
public class EAIMessageService extends AbstractDataService<EAIMessageEntity, String, EAIMessageRepository> {

	private  final UserBusinessService userBusinessService;

	public Page<Tuple> selectList(EAIMessageUISearch eaiMessageUISearch, Pageable pageable, String sortname,  String sortorder) {

		QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		QServiceMessageEntity qServiceMessageEntity = QServiceMessageEntity.serviceMessageEntity;
		QRouting qRouting = QRouting.routing;
		QStandardMessageInfo qStdInfo = QStandardMessageInfo.standardMessageInfo;
		QApiStatus qApiStatus = QApiStatus.apiStatus;

		JPAQuery<Tuple> jpaQuery = createBaseQuery(eaiMessageUISearch);

		long totalCount = jpaQuery.select(QEAIMessageEntity.eAIMessageEntity.count()).fetchOne();

		// 정렬 조건 설정
	    OrderSpecifier<?> orderSpecifier = getOrderSpecifier(qeaiMessageEntity, sortname, sortorder);

		List<Tuple> eaiMessages = jpaQuery
			.select(qeaiMessageEntity
					, qServiceMessageEntity.psvintfacdsticname
					, qServiceMessageEntity.psvsysadptrbzwkgroupname
					, qRouting.nonmotivrouturiname
					, qStdInfo.apifullpath
					, qStdInfo.bzwksvckeyname
					, qApiStatus.statusCode

			)
			.limit(pageable.getPageSize())
			.offset(pageable.getOffset())
			.orderBy(orderSpecifier)
			.fetch();

		return new PageImpl<>(eaiMessages, pageable, totalCount);
	}

	public List<Tuple> selectListToExcel(EAIMessageUISearch eaiMessageUISearch) {
		return createBaseQuery(eaiMessageUISearch).fetch();
	}
	
	/*
	 * OrderSpecifier
	 */
	private OrderSpecifier<?> getOrderSpecifier(QEAIMessageEntity qeaiMessageEntity, String sortname, String sortorder) {
	    boolean isAscending = sortorder == null || "asc".equals(sortorder);
	    
	    if ("eaiSvcName".equals(sortname)) {
	        return isAscending ? 
	               qeaiMessageEntity.eaisvcname.asc() : 
	               qeaiMessageEntity.eaisvcname.desc();
	    } else if ("lastModifiedDate".equals(sortname)) {
	        return isAscending ? 
	               qeaiMessageEntity.eailastamndyms.asc() : 
	               qeaiMessageEntity.eailastamndyms.desc();
	    } else {	       
	        return qeaiMessageEntity.eailastamndyms.desc();
	    }
	}

	/**
	 * 리스트, excel 조회 쿼리 생성
	 *
	 * @param eaiMessageUISearch
	 * @return qeaiMessageEntity, qServiceMessageEntity.psvintfacdsticname,
	 *         qRouting.nonmotivrouturiname
	 */
	private JPAQuery<Tuple> createBaseQuery(EAIMessageUISearch eaiMessageUISearch) {
		QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		QServiceMessageEntity qServiceMessageEntity = QServiceMessageEntity.serviceMessageEntity;
		QRouting qRouting = QRouting.routing;
		QStandardMessageInfo qStdInfo = QStandardMessageInfo.standardMessageInfo;
		QApiStatus qApiStatus = QApiStatus.apiStatus;

		BooleanBuilder predicate = createSelectListPredicate(eaiMessageUISearch);

		return getJPAQueryFactory()
				.select(qeaiMessageEntity
						, qServiceMessageEntity.psvintfacdsticname
						, qRouting.nonmotivrouturiname
						, qStdInfo.apifullpath
						, qStdInfo.bzwksvckeyname
						, qApiStatus.statusCode
				)
				.from(qeaiMessageEntity)
				.join(qRouting)
				.on(qeaiMessageEntity.flowctrlroutname.eq(qRouting.routname))
				.leftJoin(qeaiMessageEntity.serviceMessages, qServiceMessageEntity)
				.on(qServiceMessageEntity.id.svcprcssno.eq(1))
				.leftJoin(qStdInfo)
				.on(qeaiMessageEntity.eaisvcname.eq(qStdInfo.eaisvcname))
				.leftJoin(qApiStatus)
				.on(qeaiMessageEntity.eaisvcname.eq(qApiStatus.eaisvcname))
				.where(predicate);
	}

	public BooleanBuilder createSelectListPredicate(EAIMessageUISearch eaiMessageUISearch) {

		QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		QServiceMessageEntity qServiceMessageEntity = QServiceMessageEntity.serviceMessageEntity;
		QRouting qRouting = QRouting.routing;
		QStandardMessageInfo qStdInfo = QStandardMessageInfo.standardMessageInfo;

		BooleanBuilder predicate = new BooleanBuilder();

		List<String> businesses = userBusinessService.getCurrentUserBusinessCodes();
		predicate.and(qeaiMessageEntity.eaibzwkdstcd.in(businesses));

		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchEaiSvcName())) {
			predicate.and(qeaiMessageEntity.eaisvcname.containsIgnoreCase(eaiMessageUISearch.getSearchEaiSvcName()));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchEaiBzwkDstcd())) {
			predicate
					.and(qeaiMessageEntity.eaibzwkdstcd.containsIgnoreCase(eaiMessageUISearch.getSearchEaiBzwkDstcd()));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchEaiSvcDesc())) {
			predicate.and(qeaiMessageEntity.eaisvcdesc.containsIgnoreCase(eaiMessageUISearch.getSearchEaiSvcDesc()));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchSvcMotivUsedStcd())) {
			predicate.and(qeaiMessageEntity.svcmotivusedstcd.eq(eaiMessageUISearch.getSearchSvcMotivUsedStcd()));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchFlowControl())) {
			predicate.and(qeaiMessageEntity.flowctrlroutname.eq(eaiMessageUISearch.getSearchFlowControl()));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchTranType())) {
			predicate.and(qeaiMessageEntity.trantype.eq(eaiMessageUISearch.getSearchTranType()));
		}
		if ("R".equals(eaiMessageUISearch.getRmsMenuAuth())) {
			predicate.and(qeaiMessageEntity.trantype.ne("S"));
		}

		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchExtBizCd())) {
			predicate.and(qeaiMessageEntity.extbizcd.containsIgnoreCase(eaiMessageUISearch.getSearchExtBizCd()));
		}

		if (StringUtils.isNotBlank(eaiMessageUISearch.getTranChangeSim())) {
			predicate.and(qeaiMessageEntity.eaisvcname.endsWith("2"));
		}
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchRefKey())) {
			predicate.and(qeaiMessageEntity.refkey.containsIgnoreCase(eaiMessageUISearch.getSearchRefKey()));
		}

		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchQueueName())) {
			predicate
					.and(qeaiMessageEntity.flowctrlroutname.eq(qRouting.routname))
					.and(qRouting.nonmotivrouturiname.containsIgnoreCase(eaiMessageUISearch.getSearchQueueName()));

		}

		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchPsvintfacdsticName())) {
			predicate
					.and(qServiceMessageEntity.id.svcprcssno.eq(1))
					.and(qServiceMessageEntity.psvintfacdsticname
							.containsIgnoreCase(eaiMessageUISearch.getSearchPsvintfacdsticName()));
		}
		
		if (StringUtils.isNotBlank(eaiMessageUISearch.getSearchApiFullPath())) {
			predicate
				.and(qStdInfo.apifullpath.contains(eaiMessageUISearch.getSearchApiFullPath()));
		}
		
		return predicate;
	}

	public Page<RoutingEaiMsgDto> findAll(Pageable pageable, RoutingEaiMsgSearch routingEaiMsgSearch) {

		List<RoutingEaiMsgDto> result =  routingEaiMsgDtoList(pageable, routingEaiMsgSearch);
		Map<Pair<String, String>, Integer> runCounts = getRunCounts(routingEaiMsgSearch.getSearchBaseYmd());

		List<RoutingEaiMsgDto> updateResult =  result.stream()
				.map(dto -> {
					Pair<String, String> key = Pair.of(dto.getEaiSvcName(), dto.getEaiSevrInstncName());
					dto.setTot(runCounts.getOrDefault(key, 0));
					return dto;
				})
				.collect(Collectors.toList());

		return new PageImpl<>(updateResult, pageable, updateResult.size());
	}

	private List<RoutingEaiMsgDto> routingEaiMsgDtoList(Pageable pageable,  RoutingEaiMsgSearch routingEaiMsgSearch) {
		QEAIMessageEntity qEaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		QServiceMessageEntity qServiceMessageEntity = QServiceMessageEntity.serviceMessageEntity;
		QRouting qRouting = QRouting.routing;
		QAdapter qAdapter = QAdapter.adapter;

		BooleanBuilder predicate = buildPredicate(qEaiMessageEntity, qServiceMessageEntity, qAdapter, routingEaiMsgSearch);

		return getJPAQueryFactory()
				.select(Projections.constructor(RoutingEaiMsgDto.class ,
						qEaiMessageEntity.eaisvcname ,
						qAdapter.eaisevrinstncname ,
						qEaiMessageEntity.svcmotivusedstcd ,
						qServiceMessageEntity.psvintfacdsticname ,
						Expressions.constant(0),
						qEaiMessageEntity.flowctrlroutname ,
						qRouting.nonmotivrouturiname ,
						qEaiMessageEntity.eaibzwkdstcd ))
				.from(qEaiMessageEntity)
				.leftJoin(qServiceMessageEntity).on(qEaiMessageEntity.eaisvcname.eq(qServiceMessageEntity.id.eaisvcname)
						.and(qServiceMessageEntity.id.svcprcssno.eq(1)))
				.join(qRouting).on(qEaiMessageEntity.flowctrlroutname.eq(qRouting.routname))
				.join(qAdapter).on(qEaiMessageEntity.gstatsysadptrbzwkgroupname.eq(qAdapter.id.adptrbzwkgroupname))
				.where(predicate)
				.orderBy(qEaiMessageEntity.flowctrlroutname.asc(), qAdapter.eaisevrinstncname.asc(), qEaiMessageEntity.eaisvcname.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();
	}

	public Map<Pair<String, String>, Integer> getRunCounts(String baseYmd) {
		QStatLog qStatLog = QStatLog.statLog;

		List<Tuple> results = getJPAQueryFactory()
				.select(qStatLog.id.eaisvcname, qStatLog.id.eaisevrinstncname, qStatLog.wholprcssnoitm.sum())
				.from(qStatLog)
				.where(qStatLog.id.baseymd.eq(baseYmd))
				.groupBy(qStatLog.id.eaisvcname, qStatLog.id.eaisevrinstncname)
				.fetch();

		return results.stream().collect(Collectors.toMap(
				result -> Pair.of(result.get(qStatLog.id.eaisvcname), result.get(qStatLog.id.eaisevrinstncname)), // key
				result -> result.get(qStatLog.wholprcssnoitm.sum()).intValue()
		));
	}

	private BooleanBuilder buildPredicate(QEAIMessageEntity qEaiMessageEntity, QServiceMessageEntity qServiceMessageEntity,
										  QAdapter qAdapter, RoutingEaiMsgSearch routingEaiMsgSearch) {

		BooleanBuilder predicate = new BooleanBuilder();

		if(StringUtils.isNotBlank(routingEaiMsgSearch.getSearchEaiSvcName())) {
			predicate = predicate.and(qEaiMessageEntity.eaisvcname.containsIgnoreCase(routingEaiMsgSearch.getSearchEaiSvcName()));
		}

		if(StringUtils.isNotBlank(routingEaiMsgSearch.getSearchFlowCtrlRoutName())) {
			predicate = predicate.and(qEaiMessageEntity.flowctrlroutname.eq(routingEaiMsgSearch.getSearchFlowCtrlRoutName()));
		}

		if(StringUtils.isNotBlank(routingEaiMsgSearch.getSearchEaiSevrInstncName())) {
			predicate = predicate.and(qAdapter.eaisevrinstncname.eq(routingEaiMsgSearch.getSearchEaiSevrInstncName()));
		}

		if(StringUtils.isNotBlank(routingEaiMsgSearch.getSearchSvcMotivUsedStcd())) {
			predicate = predicate.and(qEaiMessageEntity.svcmotivusedstcd.eq(routingEaiMsgSearch.getSearchSvcMotivUsedStcd()));
		}

		if(StringUtils.isNotBlank(routingEaiMsgSearch.getSearchPsvIntfaCdSticName())) {
			predicate = predicate.and(qServiceMessageEntity.psvintfacdsticname.eq(routingEaiMsgSearch.getSearchPsvIntfaCdSticName()));
		}

		return predicate;
	}

	public Page<ApiScopeDto> findAll(Pageable pageable, ApiScopeSearch apiScopeSearch) {
		QEAIMessageEntity qEaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		QStandardMessageInfo qStandardMessageInfo = QStandardMessageInfo.standardMessageInfo;
		QScopeEntity qScopeEntity = QScopeEntity.scopeEntity;
		QScopeInfo qScopeInfo = QScopeInfo.scopeInfo;

		BooleanExpression predicate = booleanPredicate(qEaiMessageEntity, qScopeEntity, qScopeInfo, apiScopeSearch);

		List<ApiScopeDto> result =  getJPAQueryFactory()
				.select(Projections.constructor(ApiScopeDto.class ,
						qEaiMessageEntity.eaisvcname ,
						qEaiMessageEntity.eaisvcdesc ,
						qScopeEntity.id.scopeid ,
						qScopeEntity.id.bzwksvckeyname ,
						qScopeInfo.scopeName  ,
						qStandardMessageInfo.apifullpath
						)
				 )
				.from(qEaiMessageEntity)
				.join(qStandardMessageInfo)
				.on(qEaiMessageEntity.eaisvcname.eq(qStandardMessageInfo.eaisvcname))
				.join(qScopeEntity)
				.on(qStandardMessageInfo.bzwksvckeyname.eq(qScopeEntity.id.bzwksvckeyname))
				.join(qScopeInfo)
				.on(qScopeEntity.id.scopeid.eq(qScopeInfo.scopeId))
				.where(predicate)
				.orderBy(qScopeEntity.id.bzwksvckeyname.asc())
				.fetch();

		return new PageImpl<>(result, pageable, result.size());
	}

	private BooleanExpression booleanPredicate(QEAIMessageEntity qEaiMessageEntity, QScopeEntity qScopeEntity,
											   QScopeInfo qScopeInfo, ApiScopeSearch apiScopeSearch) {

		BooleanExpression predicate = qScopeEntity.id.scopeid.equalsIgnoreCase(apiScopeSearch.getSearchScopeId());
//		BooleanExpression predicate = qEaiMessageEntity.eaisvcdesc.containsIgnoreCase(apiScopeSearch.getSearchEaiSvcDesc());

//		if(StringUtils.isNotBlank(apiScopeSearch.getSearchBzwkSvcKeyName())) {
//			predicate = predicate.and(qScopeEntity.id.bzwksvckeyname.containsIgnoreCase(apiScopeSearch.getSearchBzwkSvcKeyName()));
//		}
//
//		if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeId())) {
//			predicate = predicate.and(qScopeEntity.id.scopeid.containsIgnoreCase(apiScopeSearch.getSearchScopeId()));
//		}
//
//		if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeName())) {
//			predicate = predicate.and(qScopeInfo.scopeName.containsIgnoreCase(apiScopeSearch.getSearchScopeName()));
//		}

		return predicate;
	}

	public Page<EAIMessageEntity> findAll(Pageable pageable, String eaiSvcName) {
		BooleanExpression predicate = QEAIMessageEntity.eAIMessageEntity.eaisvcname.containsIgnoreCase(eaiSvcName);
		return repository.findAll(predicate, pageable);
	}

	public List<EAIMessageEntity> findByEaisvcnameList(List<String> eaiSvcNameList) {
		QEAIMessageEntity qEaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
		return getJPAQueryFactory().selectFrom(qEaiMessageEntity)
				.where(qEaiMessageEntity.eaisvcname.in(eaiSvcNameList))
				.fetch();
	}
}
