package cd.casic.ci.process.engine.manager.impl;

import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.engine.enums.ContextStateEnum;
import cd.casic.ci.process.engine.manager.RunContextManager;
import cd.casic.ci.process.engine.manager.WorkerManager;
import cd.casic.ci.process.engine.message.TaskRunMessage;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.worker.base.BaseWorker;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Component
@Slf4j
public class DefaultWorkerManager extends WorkerManager {
    private static final String basePackage = "cd.casic.ci.process.engine.worker";
    private Set<BeanDefinition> candidates;
    private ApplicationContext applicationContext;
    private Map<String,BaseWorker> taskTypeWorkerMap = null;
    @Resource
    private ThreadPoolTaskExecutor workerExecutor;
    @Resource
    private RunContextManager contextManager;

    private void setTaskTypeWorker(Map<String, BaseWorker> taskTypeWorker) {
        this.taskTypeWorkerMap = taskTypeWorker;
    }

    @PostConstruct
    public void init(){
        ClassPathScanningCandidateComponentProvider provider =
                new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(WorkAtom.class));
        candidates = provider.findCandidateComponents(basePackage);
        taskTypeWorkerMap = new HashMap<>(candidates.size());
        for (BeanDefinition candidate : candidates) {
            String beanClassName = candidate.getBeanClassName();
            Class<?> workerClass = null;
            try {
                workerClass = Class.forName(beanClassName);
            } catch (ClassNotFoundException e) {
                continue;
            }
            Object bean = applicationContext.getBean(workerClass);
            if (bean instanceof BaseWorker worker) {
                WorkAtom annotation = worker.getClass().getAnnotation(WorkAtom.class);
                String taskType = annotation.taskType();
                if (StringUtils.isNotEmpty(taskType)) {
                    taskTypeWorkerMap.put(taskType,worker);
                }
            }
        }

        log.info("================WorkerManager初始化完毕");
    }
    @Override
    public void onMessage(TaskRunMessage message) {
        log.info("===============接收到消息================");
        try {
            PipTask task = message.getTask();
            BaseRunContext context = contextManager.getContext(task.getId());
            if (context==null) {
                throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"未找到对应上下文");
            }
            ContextStateEnum byCode = ContextStateEnum.getByCode(context.getState().get());
            if (ContextStateEnum.SUSPEND.equals(byCode)) {
                // todo 可以添加进内存或者什么别的地方中，等待审批以后重新加入队列
                throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"当前task为挂起状态，进入队列重新执行");
            }
            String taskType = task.getTaskType();
            BaseWorker baseWorker = taskTypeWorkerMap.get(taskType);
            if (baseWorker==null) {
                throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"找不到worker");
            }
            baseWorker.setContextKey(task.getId());
            workerExecutor.execute(baseWorker);
        }catch (Exception e){
            log.error("=======================workerManager：",e);
            // 这一块报错应该只可能是因为,找不到对应worker 线程池的拒绝策略 抛出错误等待redis重新消费
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"");
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
