package com.yeejoin.amos.boot.module.common.biz.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.typroject.tyboot.core.rdbms.service.BaseService;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService;
import com.yeejoin.amos.boot.module.common.api.dto.FailureAuditDto;
import com.yeejoin.amos.boot.module.common.api.dto.FailureDetailsDto;
import com.yeejoin.amos.boot.module.common.api.dto.FailureRepairlogDto;
import com.yeejoin.amos.boot.module.common.api.entity.FailureAudit;
import com.yeejoin.amos.boot.module.common.api.entity.FailureDetails;
import com.yeejoin.amos.boot.module.common.api.enums.FailureStatuEnum;
import com.yeejoin.amos.boot.module.common.api.mapper.FailureDetailsMapper;
import com.yeejoin.amos.boot.module.common.api.service.IFailureAuditService;
import com.yeejoin.amos.boot.module.common.api.service.IFailureDetailsService;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;

import rx.internal.util.LinkedArrayList;

/**
 * 服务实现类
 *
 * @author system_generator
 * @date 2021-08-04
 */
@Service
public class FailureDetailsServiceImpl extends BaseService<FailureDetailsDto, FailureDetails, FailureDetailsMapper>
		implements IFailureDetailsService {

	@Autowired
	SourceFileServiceImpl sourceFileServiceImpl;

	@Autowired
	WorkflowFeignService workflowFeignService;

	@Value("${failure.work.flow.processDefinitionKey}")
	private String processDefinitionKey;

	@Autowired
	FailureAuditServiceImpl failureAuditServiceImpl;

	@Autowired
	IFailureAuditService failureAuditService;

	@Autowired
	FailureRepairlogServiceImpl failureRepairlogService;

	public static String EMERGENCY_COMMAND = "应急指挥科";

	private final Logger logger = LoggerFactory.getLogger(FailureDetailsServiceImpl.class);

	public static Integer SELECY_ALL = 6;
	public static Integer SELECY_STATUS = 7;
	public static Integer SELECY_ISUBMIT = 8;

	/**
	 * 分页查询
	 */
	public Page<FailureDetailsDto> queryForFailureDetailsPage(Page<FailureDetailsDto> page, Long currentStatus,
			AgencyUserModel userInfo) {
		if (currentStatus == null) {
			return this.queryForPage(page, "submission_time", true);
		}
		return this.queryForPage(page, "submission_time", true, currentStatus);
	}

	public Page<FailureDetailsDto> queryForFailureDetailsPage(Page<FailureDetailsDto> page, Long currentStatus,
			AgencyUserModel userInfo, Integer type) {

		if (currentStatus == null || type.equals(SELECY_ALL)) {
			return this.queryForPage(page, "submission_time", true);
		}
		if (type.equals(SELECY_ISUBMIT)) {
			if (currentStatus == null || ObjectUtils.isNotEmpty(userInfo)) {
				String submissionPid = userInfo.getUserId();
				queryForPage(page, submissionPid);
			}
			return null;
		}
		return this.queryForPage(page, "submission_time", true, currentStatus);
	}

	/**
	 * 我发起分页查询
	 */
	public Page<FailureDetailsDto> queryForPage(Page<FailureDetailsDto> page, String userId) {
		if (userId == null) {
			return null;
		}
		return this.queryForPage(page, "submission_time", true, userId);
	}

	/**
	 * 列表查询 示例
	 */
	public List<FailureDetailsDto> queryForFailureDetailsList() {
		return this.queryForList("", false);
	}

	/**
	 * 根据状态查询
	 */
	public List<FailureDetails> queryForFailureDetailsList(Long currentStatus) {
		QueryWrapper<FailureDetails> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("current_status", currentStatus).orderByDesc("submission_time");
		return baseMapper.selectList(queryWrapper);

	}

	/**
	 * 流程日志
	 */
	public List<Map> repairLog(Long currentStatus) {

		return null;
	}

	/**
	 * 查询任务状态数量
	 */
	public Integer queryStatusCount(Long currentStatus) {
		QueryWrapper<FailureDetails> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("current_status", currentStatus);
		return baseMapper.selectCount(queryWrapper);
	}

	/**
	 * 发起故障保修单
	 * 
	 * @throws Exception
	 */
	@Transactional
	public Object savemodel(FailureDetailsDto failureDetailsDto, ReginParams userInfo) throws Exception {
		String businessKey = buildOrderNo();
		JSONObject body = new JSONObject();
		body.put("businessKey", businessKey);
		body.put("processDefinitionKey", processDefinitionKey);
		JSONObject jsonObject = workflowFeignService.startByVariable(body);
		if (jsonObject == null) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			// return CommonResponseUtil.failure("启动流程失败");
		}
		JSONObject instance = jsonObject.getJSONObject("data");
		if (instance == null) {
			// return CommonResponseUtil.failure("无提交隐患权限");
		}
		failureDetailsDto.setCurrentStatus(FailureStatuEnum.WAITING_AUDIT.getCode());
		// 拿到流程processId
		failureDetailsDto.setProcessId(instance.getString("id"));
		FailureDetailsDto model = null;
		try {
			if (ObjectUtils.isNotEmpty(failureDetailsDto.getAttachment())) {
				sourceFileServiceImpl.saveSourceFile(failureDetailsDto.getSequenceNbr(), failureDetailsDto.getAttachment());
			}

			// 发起主表流程 并添加至报修日志
			failureDetailsDto.setSubmissionTime(new Date());
			model = this.createWithModel(failureDetailsDto);
			Long faultId = model.getSequenceNbr();
			String processAuditor = model.getRecUserName();
			String processResult = "提交报修单";
			String processDepartment = "1111";
			Date processTime = model.getSubmissionTime();
			repairlog(faultId, processAuditor, processTime, processDepartment, processResult);

			FailureAuditDto failureAuditDto = new FailureAuditDto();
			failureAuditDto.setAuditor(model.getRecUserName());
			failureAuditDto.setFaultId(model.getSequenceNbr());
			failureAuditDto.setAuditOpinion("已发起");
			failureAuditDto.setAuditTime(new Date());
			failureAuditDto.setIsDelete(true);
			failureAuditDto.setAuditResult(5);
			if (ObjectUtils.isNotEmpty(failureAuditDto)) {
				failureAuditServiceImpl.savemodel(failureAuditDto, userInfo);
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("添加故障维修信息到数据库失败");
			return false;
			// return CommonResponseUtil.failure("添加失败");
		}
		if (ObjectUtils.isNotEmpty(model)) {
			excuteTask(instance.getString("id"), userInfo, null);
		}
		return true;
	}

	/**
	 * 添加报修日志
	 */
	public void repairlog(Long faultId, String processAuditor, Date processTime, String processDepartment,
			String processResult) {
		FailureRepairlogDto failureRepairlogDto = new FailureRepairlogDto();
		failureRepairlogDto.setFaultId(faultId);
		failureRepairlogDto.setProcessAuditor(processAuditor);
		failureRepairlogDto.setProcessTime(processTime);
		failureRepairlogDto.setProcessDepartment(processDepartment);
		failureRepairlogDto.setProcessResult(processResult);
		failureRepairlogDto.setIsDelete(false);
		failureRepairlogService.createWithModel(failureRepairlogDto);
	}

	public boolean excuteTask(Long sequenceNbr, ReginParams userInfo, String condition) {
		HashMap<String, Object> conditionMap = new HashMap<String, Object>();
		conditionMap.put("condition", Integer.parseInt(condition));
		Map<String, Object> map = checkExcuteTaskAuthMap(sequenceNbr, userInfo);
		try {
			if (Boolean.parseBoolean(map.get("checkFlag").toString())) {
				workflowFeignService.pickupAndCompleteTask(map.get("taskId").toString(), conditionMap);
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	public boolean excuteTask(String procressId, ReginParams userInfo, String condition) throws Exception {
		HashMap<String, Object> conditionMap = new HashMap<String, Object>();
		conditionMap.put("condition", condition);
		JSONObject teskObject = workflowFeignService.getTaskList(procressId);
		if (ObjectUtils.isNotEmpty(teskObject)) {
			JSONArray taskDetailArray = teskObject.getJSONArray("data");
			for (Object obj : taskDetailArray) {
				JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
				workflowFeignService.pickupAndCompleteTask(detail.getString("id"), conditionMap);
			}
		}
		return true;
	}

	public Object getNextTaskGroupName(String procressId) {
		JSONObject teskObject = workflowFeignService.getTaskList(procressId);
		JSONArray taskDetailArray = teskObject.getJSONArray("data");
		String currentRoleName = "";
		for (Object obj : taskDetailArray) {
			JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
			JSONObject taskGroupNameObject = workflowFeignService.getTaskGroupName(detail.getString("id"));
			for (Object object : taskGroupNameObject.getJSONArray("data")) {
				JSONObject taskGroupNameDetail = JSONObject.parseObject(JSONObject.toJSONString(object));
				currentRoleName = currentRoleName + taskGroupNameDetail.getString("groupId") + ",";
			}
		}
		return currentRoleName;
	}

	public boolean checkExcuteTaskAuth(Long sequenceNbr, ReginParams userInfo) {
		Map<String, Object> map = this.checkExcuteTaskAuthMap(sequenceNbr, userInfo);
		return Boolean.parseBoolean(map.get("checkFlag").toString());
	}

	public Map<String, Object> checkExcuteTaskAuthMap(Long sequenceNbr, ReginParams userInfo) {
		// 获取当前登录用户的角色
		String currentLoginUserRole = userInfo.getRole().getRoleName();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("checkFlag", false);
		FailureDetailsDto failureDetailsDto = this.queryBySeq(sequenceNbr);
		// 获取送达部门的ID
		Integer failureEquipmentId = failureDetailsDto.getFailureEquipmentId();
		// 获取上一级操作部门的Id
		FailureDetails details = this.baseMapper.selectById(sequenceNbr);
		String procressId = details.getProcessId();
		Long seq = userInfo.getDepartment().getSequenceNbr();
		JSONObject teskObject = workflowFeignService.getTaskList(procressId);
		if (ObjectUtils.isNotEmpty(teskObject)) {
			JSONArray taskDetailArray = teskObject.getJSONArray("data");
			for (Object obj : taskDetailArray) {
				JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
				String name = detail.getString("name");
				JSONObject taskGroupNameObject = workflowFeignService.getTaskGroupName(detail.getString("id"));
				// 获取流程中原本设置的当前节点的执行权限
				JSONArray taskGroupNameDetail = taskGroupNameObject.getJSONArray("data");
				// 如果拿不到当前任务的执行角色，则返回校验失败
				if (ObjectUtils.isEmpty(taskGroupNameDetail)) {
					continue;
				}
				String defaultExecutionRoleProcess = taskGroupNameDetail.getJSONObject(0).getString("groupId");
				// 判断当前登录人的角色是不是与流程中设置的当前任务节点权限一致，一致则执行，不一致则退出
				if (!defaultExecutionRoleProcess.equals(currentLoginUserRole)) {
					continue;
				}
				// 当流程节点为应急指挥科时，需要判断当前用户所在的部门id和前面处理的用户部门id是否一致
				if (name.contains(EMERGENCY_COMMAND)) {
					FailureAudit failureAuditDetail = failureAuditService.findByFaultId(sequenceNbr);
					Long auditDepartmentId = failureAuditDetail.getAuditDepartmentId();
					if (auditDepartmentId.intValue() == seq.intValue()) {
						map.put("taskId", detail.getString("id"));
						map.put("checkFlag", true);
						break;
					}
				} else {
					// 判断当前节点任务属于送达部门节点时需要判断当前登录人所在的部门id是否与表单发起时设置的送达部门一致
					if (failureEquipmentId.intValue() == seq.intValue()) {
						map.put("taskId", detail.getString("id"));
						map.put("checkFlag", true);
						break;
					}
				}
			}
		}
		return map;
	}

	/**
	 * 獲取待處理的任務數量
	 * 
	 * @param userInfo
	 * @return
	 */
	public int getPendingCount(ReginParams userInfo) {
		int countNum = 0;
		// 获取当前登录人的部门id
		Long seq = userInfo.getDepartment().getSequenceNbr();
		// 获取同角色信息的我的待办任务
		JSONObject taskListJson = workflowFeignService.getTasksNoAuth(processDefinitionKey,
				userInfo.getUserModel().getUserId());
		JSONArray taskList = JSONArray.parseArray(JSONObject.toJSONString(taskListJson.getString("data")));
		for (Object i : taskList) {
			JSONObject task = JSONObject.parseObject(JSONObject.toJSONString(i));
			String procressId = task.getString("processInstanceId");
			// 通过流程ID查找当前的故障报修表ID 的信息
			LambdaQueryWrapper<FailureDetails> wrapper = new LambdaQueryWrapper<FailureDetails>();
			wrapper.eq(FailureDetails::getProcessId, procressId);
			FailureDetails failureDetails = this.baseMapper.selectOne(wrapper);
			// 通过故障报修单查找创建人的部门ID
			FailureAudit failureAuditDetail = failureAuditService.findByFaultId(failureDetails.getSequenceNbr());
			// 再去判断当前的任务节点信息是不是维修部门，是的话将于第一次填报保单的操作人部门id进行匹配，符合将视作为一条合法的待办任务
			if (task.getString("name").contains(EMERGENCY_COMMAND)) {
				Long auditDepartmentId = failureAuditDetail.getAuditDepartmentId();
				if (auditDepartmentId.intValue() == seq.intValue()) {
					countNum++;
					continue;
				}
			} else {
				// 判断当前节点任务属于送达部门节点时需要判断当前登录人所在的部门id是否与表单发起时设置的送达部门一致
				if (failureDetails.getFailureEquipmentId().intValue() == seq.intValue()) {
					countNum++;
					continue;
				}
				}
		}
		return countNum;
	}

	public Object getCurrentProcessHistoryTask(Long id) {
		FailureDetailsDto failureDetailsDto = this.queryBySeq(id);
		String processId = failureDetailsDto.getProcessId();
		JSONObject object=	workflowFeignService.queryHistoryTaskListByProcessId(processId);
		JSONArray  datArray=null;
		if(ObjectUtils.isNotEmpty(object)) {
			 datArray=object.getJSONArray("data");
		}
		List<Object> list = new ArrayList<Object>();
		if(datArray!=null) {
			datArray.stream().forEach(i->{
				JSONObject detail =	JSONObject.parseObject(JSONObject.toJSONString(i));
				if(detail.containsKey("operator") && !detail.getString("name").equals("维修中")) {
					//从流程记录表中拿到处理人的名称
					detail.replace("operator", null);
					list.add(object);
				}
			});
		}
		return list;
	}

	public static String buildOrderNo() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		String newDate = sdf.format(new Date());
		String result = "";
		Random random = new Random();
		for (int i = 0; i < 3; i++) {
			result += random.nextInt(10);
		}
		return newDate + result;
	}

}