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

import com.eactive.eai.data.entity.onl.logger.EAILog;
import com.eactive.eai.data.entity.onl.logger.EAILogId;
import com.eactive.eai.data.entity.onl.logger.QEAILog;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.QUserBusiness;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository
public class EAILogRepositoryImpl implements EAILogRepository {

	private EntityManager em;
	
	@PersistenceContext
	public void setEm(EntityManager em) {
		this.em = em;
	}

	@Override
	public Page<EAILogDto> findAll(Class<? extends EAILog> clazz, Pageable pageable, EAILogSearch eaiLogSearch) {

		QEAILog qeaiLog = QEAILog.eAILog;
		EntityPathBase<?> entityPathBase = new EntityPathBase<>(clazz, qeaiLog.getMetadata().getName());

		QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;

		JPAQuery<?> query = new JPAQueryFactory(em).from(entityPathBase);
		appendConditions(eaiLogSearch, qeaiLog, entityPathBase, query);

		long totalCount = query.select(qeaiLog.id.msgdpstyms.count()).fetchOne();

		if (totalCount == 0) {
			return new PageImpl<>(new ArrayList<>(), pageable, 0);
		}

		List<EAILogDto> list = query
//				.select(Projections.constructor(EAILogDto.class, qeaiLog, qeaiMessageEntity.eaisvcdesc))
				.select(Projections.constructor(EAILogDto.class,
						qeaiLog.id, qeaiLog.trackasiskey1ctnt, qeaiLog.trackasiskey2ctnt, qeaiLog.keymgtmsgctnt,
						qeaiLog.eaisvcname, qeaiLog.extbizcd, qeaiLog.refkey, qeaiLog.clientname,
						qeaiLog.orgname, qeaiLog.msgprcssyms, qeaiLog.companycode, qeaiLog.eaierrctnt,
						qeaiMessageEntity.eaisvcdesc))
				.from(entityPathBase)
				.leftJoin(qeaiMessageEntity)
				.on(qeaiLog.eaisvcname.eq(qeaiMessageEntity.eaisvcname))
				.orderBy(qeaiLog.id.msgdpstyms.desc(), qeaiLog.id.eaisvcserno.asc(), qeaiLog.id.logprcssserno.asc())
				.limit(1000)
				.fetch();

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

	public Map<String, Long> countDetailedTransactions(Class<? extends EAILog> clazz, EAILogSearch eaiLogSearch) {
		QEAILog qeaiLog = QEAILog.eAILog;
		EntityPathBase<?> entityPathBase = new EntityPathBase<>(clazz, qeaiLog.getMetadata().getName());

		JPAQuery<?> query = new JPAQueryFactory(em).from(entityPathBase);
		appendConditions(eaiLogSearch, qeaiLog, entityPathBase, query);

		List<Tuple> results = query.select(
					qeaiLog.id.logprcssserno,    // 로그 처리 상태
					qeaiLog.id.logprcssserno.count())
				.groupBy(qeaiLog.id.logprcssserno)
				.fetch();

		Map<String, Long> reult = results.stream()
				.collect(Collectors.toMap(
						tuple -> tuple.get(0, String.class),
						tuple -> tuple.get(1, Long.class)
				));
		return reult;
	}

	private void appendConditions(EAILogSearch eaiLogSearch, QEAILog qeaiLog, EntityPathBase<?> entityPathBase, JPAQuery<?> query) {

		if (StringUtils.equalsIgnoreCase(eaiLogSearch.getAuthChk(), "Y")) {
			QUserBusiness qUserBusiness = QUserBusiness.userBusiness;
			JPAQuery<String> subQuery = new JPAQueryFactory(em)
					.select(qUserBusiness.id.eaiBzwkDstcd)
					.from(qUserBusiness)
					.where(qUserBusiness.id.userId.eq(eaiLogSearch.getLoginId()));

			query.where(qeaiLog.id.eaibzwkdstcd.in(subQuery));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchGuid())) {
			query
					.where(qeaiLog.pguid.eq(eaiLogSearch.getSearchGuid()))
					.where(qeaiLog.id.logprcssserno.eq(eaiLogSearch.getSearchLogPrcssSerno()));
			return;
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchStartTime())) {
			query
					.where(qeaiLog.id.msgdpstyms
							.between(eaiLogSearch.getSearchStartTime(), eaiLogSearch.getSearchEndTime()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiBzwkDstcd())) {
			query.where(qeaiLog.id.eaibzwkdstcd.eq(eaiLogSearch.getSearchEaiBzwkDstcd()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcSerno())) {
			query.where(qeaiLog.id.eaisvcserno.contains(eaiLogSearch.getSearchEaiSvcSerno()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcName())) {
			query.where(qeaiLog.eaisvcname.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcName()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcDesc())) {
			QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
			JPAQuery<String> subQuery = new JPAQueryFactory(em)
					.select(qeaiMessageEntity.eaisvcname)
					.from(qeaiMessageEntity)
					.where(qeaiMessageEntity.eaisvcdesc.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcDesc()));
			query.where(qeaiLog.eaisvcname.in(subQuery));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchKeyMgtMsgCtnt())) {
			query.where(qeaiLog.keymgtmsgctnt.contains(eaiLogSearch.getSearchKeyMgtMsgCtnt()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchTrackAsisKey1Ctnt())) {
			BooleanExpression predicate = qeaiLog.trackasiskey1ctnt
					.eq(eaiLogSearch.getSearchTrackAsisKey1Ctnt())
					.or(qeaiLog.trackasiskey2ctnt.eq(eaiLogSearch.getSearchTrackAsisKey1Ctnt()))
					.or(qeaiLog.trackasiskey3ctnt.eq(eaiLogSearch.getSearchTrackAsisKey1Ctnt()))
					.or(qeaiLog.trackasiskey4ctnt.eq(eaiLogSearch.getSearchTrackAsisKey1Ctnt()));
			query.where(predicate);
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchTrackAsisKey2Ctnt())) {
			BooleanExpression predicate = qeaiLog.trackasiskey1ctnt
					.eq(eaiLogSearch.getSearchTrackAsisKey2Ctnt())
					.or(qeaiLog.trackasiskey2ctnt.eq(eaiLogSearch.getSearchTrackAsisKey2Ctnt()))
					.or(qeaiLog.trackasiskey3ctnt.eq(eaiLogSearch.getSearchTrackAsisKey2Ctnt()))
					.or(qeaiLog.trackasiskey4ctnt.eq(eaiLogSearch.getSearchTrackAsisKey2Ctnt()));
			query.where(predicate);
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchTrackAsisKey3Ctnt())) {
			BooleanExpression predicate = qeaiLog.trackasiskey1ctnt
					.eq(eaiLogSearch.getSearchTrackAsisKey3Ctnt())
					.or(qeaiLog.trackasiskey2ctnt.eq(eaiLogSearch.getSearchTrackAsisKey3Ctnt()))
					.or(qeaiLog.trackasiskey3ctnt.eq(eaiLogSearch.getSearchTrackAsisKey3Ctnt()))
					.or(qeaiLog.trackasiskey4ctnt.eq(eaiLogSearch.getSearchTrackAsisKey3Ctnt()));
			query.where(predicate);
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchTrackAsisKey4Ctnt())) {
			BooleanExpression predicate = qeaiLog.trackasiskey1ctnt
					.eq(eaiLogSearch.getSearchTrackAsisKey4Ctnt())
					.or(qeaiLog.trackasiskey2ctnt.eq(eaiLogSearch.getSearchTrackAsisKey4Ctnt()))
					.or(qeaiLog.trackasiskey3ctnt.eq(eaiLogSearch.getSearchTrackAsisKey4Ctnt()))
					.or(qeaiLog.trackasiskey4ctnt.eq(eaiLogSearch.getSearchTrackAsisKey4Ctnt()));
			query.where(predicate);
		}

//		if (StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y")) {
//			query.where(qeaiLog.eaierrcd.trim().isNotEmpty());
//		}

		if (StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y")) {
			// 에러 로그가 있는 eaisevrinstncname을 찾는 서브쿼리
			// entityPathBase를 사용하여 동적 테이블에 대한 서브쿼리 생성
			JPAQuery<String> errorInstancesSubQuery = new JPAQueryFactory(em)
					.select(qeaiLog.id.eaisvcserno)
					.from(entityPathBase)  // clazz에 해당하는 테이블 사용
					.where(qeaiLog.id.msgdpstyms
							.between(eaiLogSearch.getSearchStartTime(), eaiLogSearch.getSearchEndTime()))
					.where(
							qeaiLog.eaierrcd.trim().isNotEmpty()
					)
					.distinct();

			// 찾은 eaisevrinstncname에 해당하는 모든 로그 조회
			query.where(qeaiLog.id.eaisvcserno.in(errorInstancesSubQuery));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchLogPrcssSerno())) {
			query.where(qeaiLog.id.logprcssserno.eq(eaiLogSearch.getSearchLogPrcssSerno()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchExtBizCd())) {
			query.where(qeaiLog.extbizcd.eq(eaiLogSearch.getSearchExtBizCd()));
		}

		if (StringUtils.isNotBlank(eaiLogSearch.getSearchRefKey())) {
			query.where(qeaiLog.refkey.containsIgnoreCase(eaiLogSearch.getSearchRefKey()));
		}

	}

	@Override
	public EAILogDto getById(Class<? extends EAILog> clazz, EAILogId eaiLogId) {
		QEAILog qeaiLog = QEAILog.eAILog;
		EntityPathBase<?> entityPathBase = new EntityPathBase<>(clazz, qeaiLog.getMetadata().getName());

		QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;

		return new JPAQueryFactory(em)
				.select(Projections.constructor(EAILogDto.class, qeaiLog, qeaiMessageEntity.eaisvcdesc))
				.from(entityPathBase)
				.leftJoin(qeaiMessageEntity)
				.on(qeaiLog.eaisvcname.eq(qeaiMessageEntity.eaisvcname))
				.where(qeaiLog.id.eq(eaiLogId))
				.fetchOne();
	}

	@Override
	public List<EAILog> getApiLog(Class<? extends EAILog> clazz, String apiServiceNumber) {
		QEAILog qeaiLog = QEAILog.eAILog;
		EntityPathBase<?> entityPathBase = new EntityPathBase<>(clazz, qeaiLog.getMetadata().getName());

		return new JPAQueryFactory(em).select(qeaiLog).from(entityPathBase)
				.where(qeaiLog.id.eaisvcserno.trim().eq(apiServiceNumber)).orderBy(qeaiLog.id.logprcssserno.asc())
				.fetch();
	}

}
