package com.sinosig.activiti.service.external;

import com.alibaba.fastjson.JSONObject;
import com.sinosig.activiti.ActivitiWFApplication.WebClientProperties;
import com.sinosig.activiti.feign.FeignRequestInterceptor;
import com.sinosig.activiti.feign.UniWFFeignClient;
import com.sinosig.activiti.util.domain.WFSTEPACTORDTO;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Map;

/**
 * 调用统一系统服务
 */
@Service
public class UniWFService {

    UniWFFeignClient client;

	@Autowired
	RuntimeService runtimeService;

	@Autowired
	TaskRuntime taskRuntime;

	@Autowired
	TaskService taskService;

	@Autowired
	ProcessRuntime processRuntime;

    @Autowired
    public UniWFService(Decoder decoder, Encoder encoder, Client client, Contract contract, FeignRequestInterceptor feignRequestInterceptor,
						WebClientProperties webClientProperties) {
        if (webClientProperties.getServiceId()!=null) {
    		Feign.Builder nameBuilder = Feign.builder()
                    .client(client)
                    .encoder(encoder)
                    .decoder(decoder)
                    .contract(contract)
                    .requestInterceptor(feignRequestInterceptor)
                    ;
        	this.client = nameBuilder.target(UniWFFeignClient.class,"http://" + webClientProperties.getServiceId() + "/") ;
		} else if (webClientProperties.getServiceUrl()!=null) {
			if (client instanceof LoadBalancerFeignClient) {
				client = ((LoadBalancerFeignClient) client).getDelegate();
			}
			Feign.Builder nameBuilder = Feign.builder()
                    .client(client)
                    .encoder(encoder)
                    .decoder(decoder)
                    .contract(contract)
                    .requestInterceptor(feignRequestInterceptor)
                    ;
        	this.client = nameBuilder.target(UniWFFeignClient.class, "http://" + webClientProperties.getServiceUrl() + "/") ;
		}
    }

	/**
	 * 获取下一步流程的操作者
	 * @param
	 * @return
	 */
	public WFSTEPACTORDTO calculatenextWFSTEPACTOR() {

		String wfstepactor_id="1";
		JSONObject req_param =new JSONObject();
		req_param.put("wfuserid","");
		WFSTEPACTORDTO rsp_data = client.calculatenextWFSTEPACTOR(wfstepactor_id,req_param);
        return rsp_data;
    }

	/**
	 * 工作流启动回调-实例
	 * @param instance
	 * @return
	 */
	public void wfStartCallbackByInst(ProcessInstance instance ){

		JSONObject instance_variables =getIntanceVariables(instance.getId());
		String uniWFInstanceid=instance_variables.getString("wfinstanceid");//统一实例标识
		JSONObject req_param=new JSONObject();
		req_param.put("wfinstanceid",uniWFInstanceid);
		req_param.put("wfengineinstanceid",instance.getId());
		req_param.put("starttime",new Timestamp(instance.getStartDate().getTime()));
		req_param.put("owner","system");
		req_param.put("wfstate",instance_variables.getString("workingState"));
		req_param.put("curstep","");

		client.updateWFINSTANCE(uniWFInstanceid,  req_param);
	}


	/**
	 * 工作流提交回调-实例
	 * @return
	 */
	public void wfSubmitCallbackByInst(org.activiti.api.task.model.Task task){

		//TODO 需要补充Any、All逻辑，所有步骤审批完成时，更新实例状态
		if(task.getStatus() == org.activiti.api.task.model.Task.TaskStatus.COMPLETED){

			//查询当前流程实例
			ProcessInstance instance=processRuntime.processInstance(task.getProcessInstanceId());

			JSONObject instance_variables =getIntanceVariables(instance.getId());
			String uniWFInstanceid=instance_variables.getString("wfinstanceid");//统一实例标识
			JSONObject req_param=new JSONObject();
			req_param.put("wfinstanceid",instance_variables.getString("wfinstanceid"));
			req_param.put("wfstate",instance_variables.getString("workingstate"));
			req_param.put("curstep","");
			req_param.put("Prevstep","");

			client.updateWFINSTANCE(uniWFInstanceid, req_param);
		}
	}

	/**
	 * 工作流结束回调--实例
	 * @return
	 */
	public void wfCloseCallbackByInst(String instanceId){

		//查询当前流程实例
		ProcessInstance instance=processRuntime.processInstance(instanceId);

		JSONObject instance_variables =getIntanceVariables(instance.getId());
		String uniWFInstanceid=instance_variables.getString("wfinstanceid");//统一实例标识

		JSONObject req_param=new JSONObject();
		req_param.put("wfinstanceid",instance_variables.getString("wfinstanceid"));
		req_param.put("isclose",1);
		req_param.put("wfstate","");
		req_param.put("curstep","");
		req_param.put("prevstep","");
		req_param.put("endtime",new Timestamp(new Date().getTime()));

		client.updateWFINSTANCE(uniWFInstanceid, req_param);
	}

	/**
	 * 工作流启动回调--待办
	 * @param instance
	 * @return
	 */
	public void  wfStartCallbackByTask(ProcessInstance instance){

		createUniWFTask(instance.getId());
	}

	/**
	 * 工作流提交回调--待办
	 * @param curTask
	 * @return
	 */
	public void  wfSubmitCallbackByTask(org.activiti.api.task.model.Task curTask ,JSONObject uniwfWorklist){

		if(curTask.getStatus() == org.activiti.api.task.model.Task.TaskStatus.COMPLETED){

			//查询当前流程实例
			ProcessInstance instance=processRuntime.processInstance(curTask.getProcessInstanceId());

			JSONObject instance_variables =getIntanceVariables(instance.getId());

			String uniwfWorklistId=uniwfWorklist.getString("wfworklistid");

			//完成上一份待办
			JSONObject req_param=new JSONObject();
			req_param.put("wfworklistid",uniwfWorklistId);
			req_param.put("wfinstanceid",instance_variables.getString("wfinstanceid"));
			req_param.put("wfengineworklistid",curTask.getId());
			req_param.put("done",1);
			client.updateWFWORKLIST(uniwfWorklistId,req_param);

			//TODO 当流程步骤发生变化时，即流转转至下一环节时，产生新的待办；
			if(true){
				//创建新待办
				createUniWFTask(instance.getId());
			}
		}
	}

	/**
	 * 工作流关闭回调--待办
	 * @param instanceId 流程实例标识
	 * @return
	 */
	public void wfCloseCallbackByTask(String instanceId){

		Page<org.activiti.api.task.model.Task> cur_tasks= taskRuntime.tasks(Pageable.of(0,Short.MAX_VALUE),
				TaskPayloadBuilder.tasks().withProcessInstanceId(instanceId).build());

		if(cur_tasks.getContent().size()==0)
			return ;

		for(org.activiti.api.task.model.Task cur_task : cur_tasks.getContent()){

			JSONObject req_param=new JSONObject();
			req_param.put("wfworklistid",cur_task.getId());
			req_param.put("isclose",1);

			//在统一中创建待办
			client.updateWFWORKLIST(cur_task.getId(),req_param);
		}
	}


	/**
	 * 获取流程变量
	 * @param instanceid
	 * @return
	 */
	private JSONObject getIntanceVariables(String instanceid){
		Map<String, Object> variables=runtimeService.getVariables(instanceid);  //TODO 此处希望通过instanceid查询流程参数，但activiti中仅支持通过executeid查询
		JSONObject instance_variables =new JSONObject();
		instance_variables.putAll(variables);
		return instance_variables;
	}


	/**
	 * 将当前实例的待办任务同步到统一
	 * @param instanceId
	 */
	private void createUniWFTask(String instanceId){

		//查询当前流程待办
		Page<org.activiti.api.task.model.Task> cur_tasks= taskRuntime.tasks(Pageable.of(0,Short.MAX_VALUE),
				TaskPayloadBuilder.tasks().withProcessInstanceId(instanceId).build());

		if(cur_tasks.getContent().size()==0)
			return ;

		JSONObject instance_variables =getIntanceVariables(instanceId);

		for(org.activiti.api.task.model.Task cur_task : cur_tasks.getContent()){

			JSONObject req_param=new JSONObject();
			req_param.put("wfinstanceid",instance_variables.getString("wfinstanceid"));
			req_param.put("wfengineworklistid",cur_task.getId());
			req_param.put("wfworklistname",cur_task.getName());
			req_param.put("wfuserid",cur_task.getAssignee());
			req_param.put("initiator",null);
			req_param.put("workdate",null);

			//在统一中创建待办
			client.createWFWORKLIST(req_param);
		}
	}

}
