package com.eactive.eai.rms.onl.manage.inflow.group;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

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

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.eactive.eai.data.entity.onl.inflow.InflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroupMapping;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlGroupMapping;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlGroupMappingRepository;
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlGroupRepository;
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;

@Service
public class InflowGroupControlManService extends BaseService {

	private static final Logger logger = LoggerFactory.getLogger(InflowGroupControlManService.class);

	@PersistenceContext
	EntityManager entityManager;

	@Autowired
	private InflowControlGroupRepository groupRepository;

	@Autowired
	private InflowControlGroupMappingRepository mappingRepository;

	@Autowired
	private InflowGroupControlManMapper mapper;

	@Autowired
	private EaiServerInfoService eaiServerInfoService;

	private RestTemplate restTemplate = new RestTemplate();

	/**
	 * 그룹 목록 조회
	 */
	public Page<InflowGroupControlManUI> selectGroupList(Pageable pageable, String searchGroupName, String searchUseYn) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControlGroup qGroup = QInflowControlGroup.inflowControlGroup;

		BooleanBuilder boolBuilder = new BooleanBuilder();
		if (!StringUtils.isEmpty(searchGroupName)) {
			boolBuilder.and(qGroup.groupName.contains(searchGroupName));
		}
		if (!StringUtils.isEmpty(searchUseYn)) {
			// 유량제어 미설정(useYn null)은 "사용안함" 검색 시 함께 조회되도록 처리
			boolBuilder.and("0".equals(searchUseYn) ? qGroup.useYn.eq(searchUseYn).or(qGroup.useYn.isNull()) : qGroup.useYn.eq(searchUseYn));
		}

		List<InflowControlGroup> groupList = jpaQueryFactory
				.selectFrom(qGroup)
				.where(boolBuilder)
				.orderBy(qGroup.groupId.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();

		List<InflowGroupControlManUI> uiList = groupList.stream()
				.map(mapper::toVo)
				.collect(Collectors.toList());

		long totalCount = jpaQueryFactory
				.select(qGroup.groupId.count())
				.from(qGroup)
				.where(boolBuilder)
				.fetchOne();

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

	/**
	 * 그룹 상세 조회 (매핑된 인터페이스 포함)
	 */
	public InflowGroupControlManUI selectGroupDetail(String groupId) {
		Optional<InflowControlGroup> groupOpt = groupRepository.findById(groupId);
		if (!groupOpt.isPresent()) {
			return null;
		}

		InflowGroupControlManUI ui = mapper.toVo(groupOpt.get());

		// 매핑된 인터페이스 목록 조회 (인터페이스 설명 포함)
		List<InflowGroupMappingUI> mappingList = selectMappingListWithDesc(groupId);
		ui.setInterfaceList(mappingList);

		return ui;
	}

	/**
	 * 그룹에 매핑된 인터페이스 목록 조회 (인터페이스 설명 포함)
	 */
	private List<InflowGroupMappingUI> selectMappingListWithDesc(String groupId) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QInflowControlGroupMapping qMapping = QInflowControlGroupMapping.inflowControlGroupMapping;
		QEAIMessageEntity qMessage = QEAIMessageEntity.eAIMessageEntity;

		List<Tuple> tupleList = jpaQueryFactory
				.select(qMapping, qMessage.eaisvcdesc)
				.from(qMapping)
				.leftJoin(qMessage).on(qMapping.interfaceId.eq(qMessage.eaisvcname))
				.where(qMapping.groupId.eq(groupId))
				.orderBy(qMapping.interfaceId.asc())
				.fetch();

		return tupleList.stream()
				.map(tuple -> {
					InflowGroupMappingUI mappingUI = mapper.toMappingVo(tuple.get(qMapping));
					mappingUI.setInterfaceDesc(tuple.get(qMessage.eaisvcdesc));
					return mappingUI;
				})
				.collect(Collectors.toList());
	}

	/**
	 * 그룹 저장 (INSERT/UPDATE)
	 */
	@Transactional
	public void mergeGroup(InflowGroupControlManUI ui, String modifiedBy) {
		String groupId = ui.getGroupId();
		boolean isNew = StringUtils.isEmpty(groupId);

		InflowControlGroup entity;
		if (!isNew) {
			Optional<InflowControlGroup> groupOpt = groupRepository.findById(groupId);
			if (groupOpt.isPresent()) {
				entity = groupOpt.get();
				mapper.updateToEntity(ui, entity);
			} else {
				entity = mapper.toEntity(ui);
			}
		} else {
			entity = mapper.toEntity(ui);
		}
		entity.setModifiedBy(modifiedBy);
		entity.setModifiedAt(LocalDateTime.now());
		InflowControlGroup savedEntity = groupRepository.saveAndFlush(entity);

		// 저장된 엔티티의 groupId 사용 (신규 생성 시 시퀀스에서 생성된 ID)
		String savedGroupId = savedEntity.getGroupId();

		// 매핑 정보 저장
		saveMappings(savedGroupId, ui.getInterfaceList(), modifiedBy);
	}

	/**
	 * 그룹-인터페이스 매핑 저장
	 */
	@Transactional
	public void saveMappings(String groupId, List<InflowGroupMappingUI> interfaceList, String modifiedBy) {
		// 기존 매핑 삭제
		mappingRepository.deleteByGroupId(groupId);

		// 새로운 매핑 저장
		if (interfaceList != null && !interfaceList.isEmpty()) {
			for (InflowGroupMappingUI mappingUI : interfaceList) {
				InflowControlGroupMapping mapping = new InflowControlGroupMapping();
				mapping.setInterfaceId(mappingUI.getInterfaceId());
				mapping.setGroupId(groupId);
				// 화면에서 전달된 useYn 사용, 없으면 기본값 "1"
				String useYn = StringUtils.isNotEmpty(mappingUI.getUseYn()) ? mappingUI.getUseYn() : "1";
				mapping.setUseYn(useYn);
				mapping.setModifiedBy(modifiedBy);
				mapping.setModifiedAt(LocalDateTime.now());
				mappingRepository.save(mapping);
			}
		}
	}

	/**
	 * 그룹 삭제
	 */
	@Transactional
	public void deleteGroup(String groupId) {
		// 매핑 먼저 삭제
		mappingRepository.deleteByGroupId(groupId);
		// 그룹 삭제
		groupRepository.deleteById(groupId);
	}

	/**
	 * 인터페이스 중복 등록 체크 (다른 그룹에 등록 여부)
	 * @param interfaceId 체크할 인터페이스 ID
	 * @param currentGroupId 현재 그룹 ID (수정 시 자기 그룹 제외, 신규 시 null)
	 * @return 등록된 그룹명 (미등록 시 null)
	 */
	public String checkInterfaceDuplicate(String interfaceId, String currentGroupId) {
		Optional<InflowControlGroupMapping> mappingOpt = mappingRepository.findByInterfaceId(interfaceId);
		if (!mappingOpt.isPresent()) {
			return null;
		}

		InflowControlGroupMapping mapping = mappingOpt.get();
		String existingGroupId = mapping.getGroupId();

		// 현재 그룹과 동일하면 중복 아님 (수정 시)
		if (existingGroupId.equals(currentGroupId)) {
			return null;
		}

		// 그룹명 조회
		Optional<InflowControlGroup> groupOpt = groupRepository.findById(existingGroupId);
		if (groupOpt.isPresent()) {
			return groupOpt.get().getGroupName();
		}
		return existingGroupId; // 그룹명 없으면 ID 반환
	}

	/**
	 * 인터페이스 목록 조회 (팝업용)
	 */
	public Page<InflowGroupMappingUI> selectInterfaceListForPopup(Pageable pageable, String searchName) {
		JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
		QEAIMessageEntity qMessage = QEAIMessageEntity.eAIMessageEntity;

		BooleanBuilder boolBuilder = new BooleanBuilder();
		if (!StringUtils.isEmpty(searchName)) {
			boolBuilder.and(qMessage.eaisvcname.containsIgnoreCase(searchName)
					.or(qMessage.eaisvcdesc.containsIgnoreCase(searchName)));
		}

		List<Tuple> tupleList = jpaQueryFactory
				.select(qMessage.eaisvcname, qMessage.eaisvcdesc)
				.from(qMessage)
				.where(boolBuilder)
				.orderBy(qMessage.eaisvcname.asc())
				.offset(pageable.getOffset())
				.limit(pageable.getPageSize())
				.fetch();

		List<InflowGroupMappingUI> uiList = tupleList.stream()
				.map(tuple -> {
					InflowGroupMappingUI ui = new InflowGroupMappingUI();
					ui.setInterfaceId(tuple.get(qMessage.eaisvcname));
					ui.setInterfaceDesc(tuple.get(qMessage.eaisvcdesc));
					return ui;
				})
				.collect(Collectors.toList());

		long totalCount = jpaQueryFactory
				.select(qMessage.eaisvcname.count())
				.from(qMessage)
				.where(boolBuilder)
				.fetchOne();

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

	/**
	 * 그룹 버킷 상태 조회 (모든 GW 서버에서 수집)
	 */
	@SuppressWarnings("unchecked")
	public List<Map<String, Object>> getGroupBucketStatus(String groupId) {
		List<Map<String, Object>> result = new ArrayList<>();
		List<Map<String, String>> serverList = eaiServerInfoService.getEaiServerIpList();

		for (Map<String, String> server : serverList) {
			String serverName = server.get("EAISVRINSTNM");
			String serverIp = server.get("EAISVRIP");
			String serverPort = server.get("EAISVRLSNPORT");

			Map<String, Object> serverStatus = new HashMap<>();
			serverStatus.put("serverName", serverName);
			serverStatus.put("serverIp", serverIp);
			serverStatus.put("serverPort", serverPort);

			try {
				String url = String.format("http://%s:%s/manage/inflow/group/%s/bucket-status",
						serverIp, serverPort, groupId);
				ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);

				if (response.getBody() != null && Boolean.TRUE.equals(response.getBody().get("success"))) {
					serverStatus.put("status", "online");
					serverStatus.put("data", response.getBody().get("data"));
				} else {
					serverStatus.put("status", "no_data");
					serverStatus.put("message", "그룹이 로드되지 않음");
				}
			} catch (Exception e) {
				logger.warn("버킷 상태 조회 실패 - server: {}, error: {}", serverName, e.getMessage());
				serverStatus.put("status", "offline");
				serverStatus.put("message", "서버 연결 실패");
			}

			result.add(serverStatus);
		}

		return result;
	}
}
