package com.eactive.eai.rms.onl.common.service.ums;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import com.eactive.apim.portal.portaluser.entity.PortalUser;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@Transactional(transactionManager = "transactionManagerForEMS")
public class PrivacyUsageNoticeService {

    private final ThreadPoolExecutor executorService;
    private final TransactionTemplate transactionTemplate;

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 20;
    private static final int QUEUE_CAPACITY = 1000;
    private static final long KEEP_ALIVE_TIME = 60L;

    @PersistenceContext(unitName = "entityManagerFactoryForEMS")
    private EntityManager entityManager;
    
    @Autowired
    private UmsSender umsSender;
        
    @Autowired
    private PrivacyNoticFactory messageFactory;
    
    @Autowired
    public PrivacyUsageNoticeService(
            @Qualifier("transactionManagerForEMS") PlatformTransactionManager transactionManager) {
        this.executorService = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        this.transactionTemplate = new TransactionTemplate(transactionManager);
        log.debug("PrivacyUsageNoticeService initialized with thread pool - core: {}, max: {}, queue: {}",
                CORE_POOL_SIZE, MAX_POOL_SIZE, QUEUE_CAPACITY);
    }
    
    @SuppressWarnings("unchecked")
	@Transactional(transactionManager = "transactionManagerForEMS")
    public void processMessages() {
        log.info("Starting to process pending messages");
        
        // 상태가 ACTIVE인 사용자들을 조회  
        List<PortalUser> noticeTarget = entityManager.createQuery(
                        "SELECT m FROM PortalUser m WHERE m.userStatus = :status ")                                
                .setParameter("status", "ACTIVE")                
                .getResultList();
        
        if(!noticeTarget.isEmpty()) {
        	
        	 for (PortalUser portalUser : noticeTarget) {
                 submitMessageTask(portalUser);
             }       	
        	
        } else {
        	 log.info("No notice target found!");
        }    
        
    }
    
    private void submitMessageTask(PortalUser portalUser) {
        int queueSize = executorService.getQueue().size();
        log.debug("Current queue size before submission: {}", queueSize);

        executorService.submit(() -> {
            try {
                transactionTemplate.execute(status -> {
                    try {
                        processMessage(portalUser);
                        return null;
                    } catch (Exception e) {
                        log.error("Failed to process message: {} - Error: {}",
                        		portalUser.getId(), e.getMessage(), e);                      
                        return null;
                    }
                });
            } catch (Exception e) {
                log.error("Transaction execution failed for message: {} - Error: {}",
                		portalUser.getId(), e.getMessage(), e);
            }
        });
    }
    
    public void processMessage(PortalUser portalUser) throws IOException {
        try {
            String standardMessage = messageFactory.createMessage(portalUser);
            log.debug("Processing message ID: {} ", portalUser.getId());

            umsSender.sendMessage(standardMessage);
          
            log.debug("Successfully processed and sent message ID: {}", portalUser.getId());
        } catch (Exception e) {
            log.error("Message processing failed for ID: {} - Error: {}",
            		portalUser.getId(), e.getMessage(), e);
       
            throw e;
        }
    }
    	
}
