package cn.com.ctop.check.component.execute;

import cn.com.ctop.check.component.basic.AbstractScript;
import cn.com.ctop.check.entity.CtopCheckTaskList;
import cn.com.ctop.check.service.ICtopCheckTaskExecuteLogService;
import cn.com.ctop.check.service.ICtopCheckTaskListService;
import cn.com.ctop.notice.handler.SendWeChatHandle;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.groovy.control.CompilationFailedException;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.UUIDGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.io.File;

/**
 *  Created by JQ.bi on 2020.08.11
 */
@Slf4j
@Component
public class GroovyScriptExecutor {

    private final static String ROOT_PATH = System.getProperty("user.dir");

    private final static String SCRIPT_PATH = ROOT_PATH + File.separator + "script";

    private final ApplicationContext applicationContext;

    private final ScriptProcessLogExecutor scriptProcessLogExecutor;

    private final ICtopCheckTaskListService checkTaskListService;

    private final SendWeChatHandle  sendWeChatHandle;

    private final GroovyClassLoader classLoader;

    @Autowired
    public GroovyScriptExecutor(ApplicationContext applicationContext,ScriptProcessLogExecutor scriptProcessLogExecutor,
                                ICtopCheckTaskListService checkTaskListService,SendWeChatHandle  sendWeChatHandle) {
        this.applicationContext=applicationContext;
        this.scriptProcessLogExecutor=scriptProcessLogExecutor;
        this.checkTaskListService = checkTaskListService;
        this.sendWeChatHandle=sendWeChatHandle;
        this.classLoader = new GroovyClassLoader();
        initClassPath();
    }

    public Result<Object> execute(CtopCheckTaskList script) {
        if(script.getIsDelete()||!script.getExeState()){
            return Result.error(String.format("groovy script is invalid. api_name=%s", script.getApiName()));
        }else {
            return executeScript(script);
        }
    }

    public Result<Object> execute(Integer id, String apiName) {
        CtopCheckTaskList script = checkTaskListService.queryByIdAndApiName(id,apiName);
        if (script == null) {
            return Result.error(String.format("groovy script not found. api_name=%s", apiName));
        }else {
            return executeScript(script);
        }
    }

    private Result<Object> executeScript(CtopCheckTaskList taskList){
        ClearCache();
        GroovyCodeSource groovyCodeSource = getGroovyCodeSource(taskList);
        Result<Object> response = null;
        try {
            long start=System.currentTimeMillis();
            Class scriptClass = this.classLoader.parseClass(groovyCodeSource);
            Object instance = scriptClass.newInstance();
            if (instance instanceof AbstractScript) {
                AbstractScript scriptInstance = (AbstractScript) instance;
                scriptInstance.setApplicationContext(applicationContext);
                scriptInstance.setSendWeChatHandle(sendWeChatHandle);
                scriptInstance.setCtopCheckTaskList(taskList);
                response = scriptInstance.exec();
            } else {
                scriptProcessLogExecutor.insertLogExecute(taskList,start,0L,false,false);
                log.error("script script should extends AbstractScript.");
                response=Result.error("script script should extends AbstractScript.");
            }
            long end=System.currentTimeMillis();
            scriptProcessLogExecutor.insertLogExecute(taskList,start,end);
        } catch (InstantiationException | IllegalAccessException | CompilationFailedException e) {
            scriptProcessLogExecutor.insertLogExecute(taskList,0L,0L,false,false);
            log.error("Error execute check task script. ", e);
            response=Result.error("Error execute check task script. "+e.getMessage());
        }
        return response;
    }

    private GroovyCodeSource getGroovyCodeSource(CtopCheckTaskList taskList) {
        String codeBase = "/script/" + UUIDGenerator.generate();
        GroovyCodeSource groovyCodeSource = new GroovyCodeSource(taskList.getScript(), taskList.getApiName(), codeBase);
        groovyCodeSource.setCachable(false);
        return groovyCodeSource;
    }

    private void initClassPath() {
        String libPath = SCRIPT_PATH + File.separator + "lib";
        File lib = new File(libPath);
        if (lib.exists()) {
            File[] files = lib.listFiles(pathname -> pathname.isFile() && pathname.getName().endsWith(".jar"));
            if (files != null) {
                for (File file : files) {
                    String path = file.getPath();
                    this.classLoader.addClasspath(path);
                }
            }
        }
    }

    //清除缓存
    private void ClearCache(){
        classLoader.clearCache();
    }

}
