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

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

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.eactive.apim.portal.app.entity.QCredential;
import com.eactive.eai.data.entity.onl.adapter.QAdapterGroup;
import com.eactive.eai.data.entity.onl.authserver.QClientEntity;
import com.eactive.eai.data.entity.onl.inflow.InflowControl;
import com.eactive.eai.data.entity.onl.inflow.InflowControlId;
import com.eactive.eai.data.entity.onl.inflow.QInflowControl;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlLog;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.data.jpa.AbstractDataService;
import com.eactive.eai.rms.onl.manage.inflow.history.InflowControlHistoryManUISearch;
import com.eactive.eai.rms.onl.manage.inflow.inflow.InflowControlManMapper;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;

@Service
public class InflowControlService extends AbstractDataService<InflowControl, InflowControlId, InflowControlRepository> {

	private static final String ADAPTER_TYPE_INFLOW = "01";
	private static final String INTERFACE_TYPE_INFLOW = "02";
	private static final String CLIENT_TYPE_INFLOW = "03";

	@PersistenceContext
	EntityManager entityManager;

	@PersistenceContext(unitName = "entityManagerFactoryForEMS")
	EntityManager entityManagerForEMS;

	@Autowired
	InflowControlManMapper mapper;

	// 유량제어 미설정(useyn null)은 "사용안함" 검색 시 함께 조회되도록 처리
	private static BooleanExpression useYnCondition(StringPath useYnPath, String searchUseYn) {
		return "0".equals(searchUseYn) ? useYnPath.eq(searchUseYn).or(useYnPath.isNull()) : useYnPath.eq(searchUseYn);
	}

	public Page<InflowControlServiceDto> findAllForAdapter(Pageable pageable, String searchName, String searchUseYn) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QAdapterGroup qAdapterGroup = QAdapterGroup.adapterGroup;
		QInflowControl qInflowControl = QInflowControl.inflowControl;

		BooleanBuilder boolBuilder = new BooleanBuilder();
		if (!StringUtils.isEmpty(searchName))
			boolBuilder.and(qAdapterGroup.adptrbzwkgroupname.contains(searchName));
		if (!StringUtils.isEmpty(searchUseYn))
			boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));

		BooleanBuilder adapterWherePredicate = new BooleanBuilder(qAdapterGroup.adptriodstcd
				.eq("I")
				.and(qAdapterGroup.adptrcd
						.in("RST", "HTT", "HTC")
						.or(qAdapterGroup.adptrbzwkgroupname
								.like("%_AsS%")
								.or(qAdapterGroup.adptrbzwkgroupname.like("%_AsC%")))));
		boolBuilder.and(adapterWherePredicate);

		List<Tuple> tupleList = jpaQueryFactory
				.select(qAdapterGroup.adptrbzwkgroupname, qAdapterGroup.adptrbzwkgroupdesc, qInflowControl)
				.from(qAdapterGroup)
				.leftJoin(qInflowControl)
				.on(qAdapterGroup.adptrbzwkgroupname
						.eq(qInflowControl.id.name)
						.and(qInflowControl.id.type.eq(ADAPTER_TYPE_INFLOW)))
				.where(boolBuilder)
				.orderBy(qAdapterGroup.adptrbzwkgroupname.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();
		List<InflowControlServiceDto> dtoList = tupleList
				.stream()
				.map(tuple -> toDto(qAdapterGroup, qInflowControl, tuple))
				.collect(Collectors.toList());

		long totalCount = jpaQueryFactory
				.select(qAdapterGroup.adptrbzwkgroupname.count())
				.from(qAdapterGroup)
				.leftJoin(qInflowControl)
				.on(qAdapterGroup.adptrbzwkgroupname
						.eq(qInflowControl.id.name)
						.and(qInflowControl.id.type.eq(ADAPTER_TYPE_INFLOW)))
				.where(boolBuilder)
				.fetchOne();

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

	private InflowControlServiceDto toDto(QAdapterGroup qAdapterGroup, QInflowControl qInflowControl, Tuple tuple) {
		InflowControlServiceDto dto = null;
		if (tuple.get(qInflowControl) != null)
			dto = mapper.toDto(tuple.get(qInflowControl));
		else {
			dto = new InflowControlServiceDto();
			dto.setName(tuple.get(qAdapterGroup.adptrbzwkgroupname));
			dto.setType(ADAPTER_TYPE_INFLOW);
		}
		dto.setDesc(tuple.get(qAdapterGroup.adptrbzwkgroupdesc));
		return dto;
	}

	public InflowControlServiceDto findByIdForAdapter(String adptrbzwkgroupname) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QAdapterGroup qAdapterGroup = QAdapterGroup.adapterGroup;
		QInflowControl qInflowControl = QInflowControl.inflowControl;

		Tuple tuple = jpaQueryFactory
				.select(qAdapterGroup.adptrbzwkgroupname, qAdapterGroup.adptrbzwkgroupdesc, qInflowControl)
				.from(qAdapterGroup)
				.leftJoin(qInflowControl)
				.on(qAdapterGroup.adptrbzwkgroupname
						.eq(qInflowControl.id.name)
						.and(qInflowControl.id.type.eq(ADAPTER_TYPE_INFLOW)))
				.where(qAdapterGroup.adptrbzwkgroupname.eq(adptrbzwkgroupname))
				.fetchOne();

		return toDto(qAdapterGroup, qInflowControl, tuple);
	}

	public Page<InflowControlServiceDto> findAllForInterface(Pageable pageable, String searchName, String searchUseYn) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControl qInflowControl = QInflowControl.inflowControl;
		QEAIMessageEntity qEAIMessageEntity = QEAIMessageEntity.eAIMessageEntity;

		BooleanBuilder boolBuilder = new BooleanBuilder();
		boolBuilder.and(qEAIMessageEntity.eaisvcname.contains(searchName));
		if (!StringUtils.isEmpty(searchUseYn))
			boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));

		List<Tuple> tupleList = jpaQueryFactory
				.select(qInflowControl, qEAIMessageEntity.eaisvcname, qEAIMessageEntity.eaisvcdesc)
				.from(qEAIMessageEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(INTERFACE_TYPE_INFLOW).and(qInflowControl.id.name.eq(qEAIMessageEntity.eaisvcname)))
				.where(boolBuilder)
				.orderBy(qEAIMessageEntity.eaisvcname.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();

		List<InflowControlServiceDto> dtoList = tupleList
				.stream()
				.map(tuple -> toDto(qEAIMessageEntity, qInflowControl, tuple))
				.collect(Collectors.toList());

		long totalCount = jpaQueryFactory
				.select(qEAIMessageEntity.eaisvcname.count())
				.from(qEAIMessageEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(INTERFACE_TYPE_INFLOW).and(qInflowControl.id.name.eq(qEAIMessageEntity.eaisvcname)))
				.where(boolBuilder)
				.fetchOne();
		return new PageImpl<>(dtoList, pageable, totalCount);
	}
	
	

	private InflowControlServiceDto toDto(QEAIMessageEntity qEAIMessageEntity, QInflowControl qInflowControl,
			Tuple tuple) {
		InflowControlServiceDto dto = null;
		if (tuple.get(qInflowControl) != null)
			dto = mapper.toDto(tuple.get(qInflowControl));
		else {
			dto = new InflowControlServiceDto();
			dto.setName(tuple.get(qEAIMessageEntity.eaisvcname));
			dto.setType(ADAPTER_TYPE_INFLOW);
		}
		dto.setDesc(tuple.get(qEAIMessageEntity.eaisvcdesc));
		return dto;
	}

	public InflowControlServiceDto findByIdForInterface(String eaisvcname) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControl qInflowControl = QInflowControl.inflowControl;
		QEAIMessageEntity qEAIMessageEntity = QEAIMessageEntity.eAIMessageEntity;

		Tuple tuple = jpaQueryFactory
				.select(qInflowControl, qEAIMessageEntity.eaisvcname, qEAIMessageEntity.eaisvcdesc)
				.from(qEAIMessageEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(INTERFACE_TYPE_INFLOW).and(qInflowControl.id.name.eq(qEAIMessageEntity.eaisvcname)))
				.where(qEAIMessageEntity.eaisvcname.eq(eaisvcname))
				.fetchOne();

		return toDto(qEAIMessageEntity, qInflowControl, tuple);
	}
	
	public InflowControlServiceDto findByIdForClient(String clientId) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControl qInflowControl = QInflowControl.inflowControl;
		QClientEntity qClientEntity = QClientEntity.clientEntity;

		Tuple tuple = jpaQueryFactory
				.select(qInflowControl, qClientEntity.clientid, qClientEntity.clientname)
				.from(qClientEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(CLIENT_TYPE_INFLOW)
						.and(qInflowControl.id.name.eq(qClientEntity.clientid)))
				.where(qClientEntity.clientid.eq(clientId))
				.fetchOne();

		return toDto(qClientEntity, qInflowControl, tuple);
	}

	public Page<InflowControlServiceDto> findAllForClient(Pageable pageable, String searchName, String searchUseYn) {

		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControl qInflowControl = QInflowControl.inflowControl;
		QClientEntity qClientEntity = QClientEntity.clientEntity;

		BooleanBuilder boolBuilder = new BooleanBuilder();
		boolBuilder.and(qClientEntity.clientname.contains(searchName));
		if (!StringUtils.isEmpty(searchUseYn))
			boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));

		List<Tuple> tupleList = jpaQueryFactory
				.select(qInflowControl, qClientEntity.clientid, qClientEntity.clientname)
				.from(qClientEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(CLIENT_TYPE_INFLOW)
						.and(qInflowControl.id.name.eq(qClientEntity.clientid)))
				.where(boolBuilder)
				.orderBy(qClientEntity.clientname.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();

		List<InflowControlServiceDto> dtoList = tupleList
				.stream()
				.map(tuple -> toDto(qClientEntity, qInflowControl, tuple))
				.collect(Collectors.toList());

		long totalCount = jpaQueryFactory
				.select(qClientEntity.clientname.count())
				.from(qClientEntity)
				.leftJoin(qInflowControl)
				.on(qInflowControl.id.type.eq(CLIENT_TYPE_INFLOW)
						.and(qInflowControl.id.name.eq(qClientEntity.clientid)))
				.where(boolBuilder)
				.fetchOne();
		return new PageImpl<>(dtoList, pageable, totalCount);
	}
	
	private InflowControlServiceDto toDto(QClientEntity qClientEntity, QInflowControl qInflowControl,
			Tuple tuple) {
		InflowControlServiceDto dto = null;
		if (tuple.get(qInflowControl) != null)
			dto = mapper.toDto(tuple.get(qInflowControl));
		else {
			dto = new InflowControlServiceDto();
			dto.setName(tuple.get(qClientEntity.clientid));
			dto.setType(CLIENT_TYPE_INFLOW);
		}
		dto.setDesc(tuple.get(qClientEntity.clientname));
		return dto;
	}
	
	public Page<Tuple> selectLogList(Pageable pageable, InflowControlHistoryManUISearch uiSearch) {
		QInflowControlLog qlog = QInflowControlLog.inflowControlLog;
        QInflowControlGroup qgroup = QInflowControlGroup.inflowControlGroup;
        
        JPAQuery<Tuple> jpaQuery = createBaseQuery(uiSearch);
        
        long totalCount = jpaQuery.select(QInflowControlLog.inflowControlLog.count()).fetchOne();
        
        List<Tuple> inflowControlLog = jpaQuery
        		.select(qlog, qgroup.groupName)
        		.limit(pageable.getPageSize())
        		.offset(pageable.getOffset())
        		.orderBy(qlog.id.msgdpstyms.desc())
        		.fetch();
        
        return new PageImpl<>(inflowControlLog, pageable, totalCount);
	}
	
	private JPAQuery<Tuple> createBaseQuery(InflowControlHistoryManUISearch uiSearch) {
		QInflowControlLog qInflowConfrolLog = QInflowControlLog.inflowControlLog;
        QInflowControlGroup qinflowControlGroup = QInflowControlGroup.inflowControlGroup;
        
        String startTime = StringUtils.defaultIfEmpty(uiSearch.getSearchStartTime(), "000000");
        String endTime = StringUtils.defaultIfEmpty(uiSearch.getSearchEndTime(), "235959");

        BooleanBuilder predicate = new BooleanBuilder();
        predicate
				.and(qInflowConfrolLog.id.msgdpstyms
						.between(uiSearch.getSearchStartDate() + startTime + "000",
								uiSearch.getSearchEndDate() + endTime + "999"));
        if (!StringUtils.isEmpty(uiSearch.getSearchInstanceName()))
        	predicate.and(qInflowConfrolLog.eaisevrinstncname.contains(uiSearch.getSearchInstanceName()));
        if (!StringUtils.isEmpty(uiSearch.getSearchApiName()))
        	predicate.and(qInflowConfrolLog.eaisvcname.contains(uiSearch.getSearchApiName()));
        if (!StringUtils.isEmpty(uiSearch.getSearchAdapterGroupName()))
        	predicate.and(qInflowConfrolLog.adptrbzwkgroupname.contains(uiSearch.getSearchAdapterGroupName()));

        return getJPAQueryFactory()
        		.select(
        				qInflowConfrolLog,
        				qinflowControlGroup.groupName
        		)
        		.from(qInflowConfrolLog)
        		.leftJoin(qinflowControlGroup)
        		.on(qInflowConfrolLog.adptrbzwkgroupname.eq(qinflowControlGroup.groupId))
        		.where(predicate);
		
	}

}
