package com.xxl.job.admin.controller;

import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.LogParam;
import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.GsonTool;
import com.xxl.job.core.util.XxlJobRemotingUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by xuxueli on 17/5/10.
 */
@Controller
@RequestMapping("/api")
public class JobApiController {

    @Resource
    private AdminBiz adminBiz;
	@Resource
	private XxlJobService xxlJobService;
	
	private static final Logger logger = LoggerFactory.getLogger(JobApiController.class);
    /**
     * api
     *
     * @param uri
     * @param data
     * @return
     */
    @RequestMapping("/{uri}")
    @ResponseBody
    @PermissionLimit(limit=false)
    public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {

        // valid
        if (!"POST".equalsIgnoreCase(request.getMethod())) {
            return new ReturnT<>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
        }
        if (uri==null || uri.trim().length()==0) {
            return new ReturnT<>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
        }
        if (XxlJobAdminConfig.getAdminConfig().getAccessToken()!=null
                && XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length()>0
                && !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
            return new ReturnT<>(ReturnT.FAIL_CODE, "The access token is wrong.");
        }

        // services mapping
		switch (uri) {
			case "callback":
				List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
				return adminBiz.callback(callbackParamList);
			case "registry": {
				RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
				return adminBiz.registry(registryParam);
			}
			case "registryRemove": {
				RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
				return adminBiz.registryRemove(registryParam);

			}
			default:
				return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
		}

    }
    
    @RequestMapping("/add")
    @ResponseBody
    @PermissionLimit(limit=false)
	public ReturnT<String> add(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.add(jobInfo);
	}
    
	@RequestMapping("/update")
	@ResponseBody
	@PermissionLimit(limit=false)
	public ReturnT<String> update(@RequestBody XxlJobInfo jobInfo) {
		return xxlJobService.update(jobInfo);
	}
	
	@RequestMapping("/remove")
	@ResponseBody
	@PermissionLimit(limit=false)
	public ReturnT<String> remove(@RequestBody Map<String, String> params) {
		return xxlJobService.remove(Integer.parseInt(params.get("id")));
	}
	
	@RequestMapping("/start")
	@ResponseBody
	@PermissionLimit(limit=false)
	public ReturnT<String> start(int id) {
		return xxlJobService.start(id);
	}
	
	@RequestMapping("/trigger")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<String> triggerJob(int id) {
		XxlJobInfo jobInfo = xxlJobService.loadById(id);
		Map<String, String> paramsMap = GsonTool.fromJson(jobInfo.getExecutorParam(), Map.class);
		paramsMap.put("emergentTask", "1");
		
		JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, GsonTool.toJson(paramsMap), "");
		return ReturnT.SUCCESS;
	}
	
	@Autowired
	XxlJobLogDao joblogDao;
	
	@RequestMapping("/joblog/{groupid}/{jobinfoid}")
	@ResponseBody
	@PermissionLimit(limit = false)
	public XxlJobLog findJoblog(@PathVariable(name = "groupid") int groupid, @PathVariable(name = "jobinfoid") int jobinfoid) {
		Date dateEnd = new Date();
		Date dateStart = new Date(dateEnd.getTime() - 30 * 24 * 60 * 60);
		List<XxlJobLog> jobLogs = joblogDao.pageList(0, 1, groupid, jobinfoid, dateStart, dateEnd, 0);
		return jobLogs.get(0);
	}
	
	@RequestMapping("/joblogdetail/{logid}")
	@ResponseBody
	@PermissionLimit(limit = false)
	public ReturnT<LogResult> logDetailCat(@PathVariable(name = "logid") int logid) {
		XxlJobLog jobLog = joblogDao.load(logid);
		try {
			ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
			ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logid, 1));

			// is end
            if (logResult.getContent()!=null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
                if (jobLog.getHandleCode() > 0) {
                    logResult.getContent().setEnd(true);
                }
            }
			return logResult;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
		}
	}
}
