package com.friday.executor.controller;

import com.friday.base.common.response.DubboResult;
import com.friday.base.web.response.ResponseAspect;
import com.friday.dynamic.core.ModuleService;
import com.friday.operation.api.distributor.bean.BaseTask;
import com.friday.operation.api.distributor.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping(value = "/dynamic")
@Slf4j
public class DynamicController {

    @Autowired
    private ModuleService moduleService;
    @Autowired
    private ResponseAspect responseAspect;

    @Value("${dynamic.jar}")
    private String dynamicJar;

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/checkParam", method = RequestMethod.POST)
    public Object checkParam(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody StartTaskReq req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "checkParam", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/createJobs", method = RequestMethod.POST)
    public Object createJobs(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody BaseTask req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "createJobs", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/executeJob", method = RequestMethod.POST)
    public Object executeJob(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody StandardJobInput req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "executeJob", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/onJobStateChange", method = RequestMethod.POST)
    public Object onJobStateChange(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody TaieJobStateChangeEvent req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "onJobStateChange", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/onTaskStateChange", method = RequestMethod.POST)
    public Object onTaskStateChange(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody TaieTaskStateChangeEvent req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "onTaskStateChange", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/getTaskResult", method = RequestMethod.POST)
    public Object getTaskResult(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody TaskResultFilter req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "getTaskResult", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/getData", method = RequestMethod.POST)
    public Object getData(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody DataRequest req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "getData", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/syncData", method = RequestMethod.POST)
    public Object syncData(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody DataRequest req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "syncData", req);
    }

    @RequestMapping(path = "invoke/{moduleName}/{moduleVersion}/{handlerName}/handleFile", method = RequestMethod.POST)
    public Object handleFile(@PathVariable String moduleName,
                         @PathVariable String moduleVersion,
                         @PathVariable String handlerName,
                         @RequestBody HandleFileDto req) {
        return this.invokeMethod(moduleName, moduleVersion, handlerName, "handleFile", req);
    }

    private Object invokeMethod(String moduleName, String moduleVersion, String handlerName, String methodName, Object req){
        try {
            DubboResult result = moduleService.handle(moduleName, moduleVersion, handlerName, methodName, req);
            if(result.success()){
                return responseAspect.success(result.getObject());
            }
            return responseAspect.fail(result.getMessage());
        } catch (Throwable t) {
            log.error(String.format("Invoke module handler exception: moduleName=%s, moduleVersion=%s, handlerName=%s, handlerArgs=%s",
                    moduleName, moduleVersion, handlerName, req), t);
            throw new RuntimeException("invoke module handler exception", t);
        }

    }

    @RequestMapping(path = "register/{subPath}", method = RequestMethod.POST)
    public String registerJar(@PathVariable String subPath) {
        moduleService.manualLoadAndRegister(dynamicJar + subPath);
        return "ok";
    }

    @RequestMapping(path = "queryModules", method = RequestMethod.GET)
    public Object queryModules() {
        return moduleService.queryAllModule();
    }

    @RequestMapping(value = "/remove/{moduleName}/{moduleVersion}", method = RequestMethod.POST)
    public String remove(@PathVariable String moduleName,
                         @PathVariable String moduleVersion) {
        moduleService.removeAndDestroy(moduleName, moduleVersion);
        return "ok";
    }
}
