package net.northking.cctp.se.plan.servcie;

import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.se.exec.DefaultExecThread;
import net.northking.cctp.se.plan.bean.AutoTask;
import net.northking.cctp.se.thread.ExecutorPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class PlanDeviceServiceImpl implements PlanDeviceService {

    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(PlanDeviceServiceImpl.class);

    private Map<String,DefaultExecThread> threadMap = new ConcurrentHashMap<>();

    private Map<String,Set<String>> batchMap = new HashMap<>();

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final static Lock lock = new ReentrantLock(true);

    @Override
    public void sendTask2Exec(AutoTask task, String deviceToken) {

        DefaultExecThread thread = new DefaultExecThread(task,deviceToken,true,this.rabbitTemplate);
        threadMap.put(task.getTaskId(),thread);
        lock.lock();
        try {
            Set<String> castSet = batchMap.get(task.getBatchId());
            if(CollectionUtils.isEmpty(castSet)){
                castSet = new HashSet<>();
                castSet.add(task.getTaskId());
                batchMap.put(task.getBatchId(),castSet);
            }else{
                castSet.add(task.getTaskId());
            }
        } catch (Exception e) {
            logger.error("暂存线程信息失败：",e);
        } finally {
            lock.unlock();
        }
        String type = task.getTaskType();
        if(TYPE_PC.equalsIgnoreCase(type)){
            // todo: 应该可以改成直接submit，放到线程的队列，线程空闲直接做
            try {
                for (int i = 0; i < 30; i++) {
                    if (ExecutorPool.isPCAvailable()) {
                        ExecutorPool.getPCPool().submit(thread);
                        logger.debug("任务提交执行，终止循环");
                        break;
                    } else {
                        if (i == 0) {
                            logger.debug("设备处于忙碌，最长等待30秒。。。");
                        }
                        Thread.sleep(1000L);
                        if (i == 25){
                            throw new ExecuteException("设备过于忙碌无法释放");
                        }
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new ExecuteException("获取线程被打断");
            }
        }
        if(TYPE_MOBILE.equalsIgnoreCase(type) && ExecutorPool.isMobileAvailable()){
            ExecutorPool.getMobilePool().submit(thread);
        }
        if(TYPE_INTERFACE.equalsIgnoreCase(type) && ExecutorPool.isApiAvailable()){
            ExecutorPool.getApiPool().submit(thread);
        }

    }

    @Override
    public void stopRunningExec(String batchId) {
        lock.lock();
        try {
            Set<String> castSet = batchMap.get(batchId);
            if(!CollectionUtils.isEmpty(castSet)){
                for (String next : castSet) {
                    DefaultExecThread execThread = threadMap.remove(next);
                    execThread.destroy(next);
                }
            }
        } catch (Exception e) {
            logger.error("终止任务执行失败：",e);
        } finally {
            lock.unlock();
            batchMap.remove(batchId);
        }
    }

    /**
     * 校验引擎是否可接受任务
     */
    @Override
    public boolean isEnableAcceptTask(String type) {
        if(TYPE_INTERFACE.equalsIgnoreCase(type)){
            return ExecutorPool.isApiAvailable();
        }
        if(TYPE_MOBILE.equalsIgnoreCase(type)){
            return ExecutorPool.isMobileAvailable();
        }
        return false;
    }

    @Override
    public void removeBatchInfo(String batchId) {
        lock.lock();
        try {
            Set<String> castSet = batchMap.get(batchId);
            if(!CollectionUtils.isEmpty(castSet)){
                for (String next : castSet) {
                    threadMap.remove(next);
                }
            }
        } catch (Exception e) {
            logger.error("终止任务执行失败：",e);
        } finally {
            lock.unlock();
            batchMap.remove(batchId);
        }
    }

}
