/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.security.trans.securityCommandCenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.security.common.Constant;
import org.security.desk.feign.IXYunClient;
import org.security.flow.core.constant.ProcessConstant;
import org.security.flow.core.entity.BladeFlow;
import org.security.flow.core.entity.BladeFlowDef;
import org.security.flow.core.feign.IFlowClient;
import org.security.flow.core.utils.FlowUtil;
import org.security.system.feign.ISysClient;
import org.security.system.user.vo.UserVO;
import org.security.trans.basic.service.IDepartmentService;
import org.security.trans.common.service.IFileService;
import org.security.ht.vo.common.UploadVO;
import org.security.trans.dailyDuties.service.IInspectionService;
import org.security.trans.securityCommandCenter.dto.SccAlarmPushDTO;
import org.security.trans.securityCommandCenter.entity.SccAlarmPush;
import org.security.trans.securityCommandCenter.entity.SccAnswerAlarm;
import org.security.trans.securityCommandCenter.entity.SccMsgSend;
import org.security.trans.securityCommandCenter.mapper.SccAnswerAlarmMapper;
import org.security.trans.securityCommandCenter.service.ISccAnswerAlarmService;
import org.security.trans.securityCommandCenter.service.ISccMsgSendService;
import org.security.trans.securityCommandCenter.vo.SccAlarmPushVO;
import org.security.trans.securityCommandCenter.mapper.SccAlarmPushMapper;
import org.security.trans.securityCommandCenter.service.ISccAlarmPushService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.security.trans.securityCommandCenter.vo.SccUnlocaleCheckVO;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 警情推送 服务实现类
 *
 * @author BladeX
 * @since 2022-07-13
 */
@Slf4j
@Service
@AllArgsConstructor
public class SccAlarmPushServiceImpl extends ServiceImpl<SccAlarmPushMapper, SccAlarmPush> implements ISccAlarmPushService {

	private final IFileService fileService;
	private final ISccMsgSendService sccMsgSendService;
	private final IDepartmentService departmentService;
	private final IFlowClient flowClient;
	private final ISysClient sysClient;
	private final SccAnswerAlarmMapper answerAlarmMapper;
	private final IXYunClient xYunClient;
	private final IInspectionService inspectionService;

	@Override
	public IPage<SccAlarmPushVO> selectSccAlarmPushPage(IPage<SccAlarmPushVO> page, SccAlarmPushDTO sccAlarmPushDTO) {
		List<SccAlarmPushVO> vos;
		//推送警情菜单列表页数据获取
		if (Constant.MENU_TYPE_ZERO.equals(sccAlarmPushDTO.getMenuType())){
			log.info("==============获取推送警情菜单列表页数据开始==============");
			vos = baseMapper.selectSccAlarmPushPage(page, sccAlarmPushDTO);
			if (Func.isNotEmpty(vos)){
				vos.forEach(item -> {
					item.setButtonStatus(Constant.BUTTON_STATE_ZERO);
					//若该警情信息已推送/已提报则该记录只能查看不能操作
					if (Constant.PUSH_STATE_ONE.equals(item.getPushState()) || Constant.PUSH_STATE_TWO.equals(item.getPushState())) {
						item.setButtonStatus(Constant.BUTTON_STATE_THREE);
					}
					item.setReceiveDept(departmentService.getById(item.getReceiveDept()).getDeptName());
				});
			}
			log.info("==============获取推送警情菜单列表页数据结束==============");
		}//警情接收菜单获取警情消息，只有指定角色能看到推送的警情信息（一个用户可能有多个角色）
		else {
			log.info("==============获取警情接收菜单获取警情消息开始==============");
			vos = baseMapper.selectSccAlarmPushDetailPage(page, sccAlarmPushDTO,Arrays.asList(AuthUtil.getUser().getRoleId().split(",")));
			if (Func.isNotEmpty(vos)){
				vos.forEach(item -> {
					item.setButtonStatus(Constant.BUTTON_STATE_THREE);
					//待推送/被驳回/审批撤回且部门id为当前登录人部门的状态可以编辑
					if ((Constant.PUSH_STATE_ONE.equals(item.getPushState())
						|| Constant.HANDIN_STATE_REFUSE.equals(item.getState())
						|| ProcessConstant.CANCEL_STATE.equals(item.getState()))
						&& AuthUtil.getDeptId().equals(item.getReceiveDept())) {
						item.setButtonStatus(Constant.BUTTON_STATE_ZERO);
					}
					item.setReceiveDept(departmentService.getById(item.getReceiveDept()).getDeptName());
				});
			}
			log.info("==============获取警情接收菜单获取警情消息结束==============");
		}
		List<SccAlarmPushVO> collect = vos.stream().sorted(Comparator.comparing(SccAlarmPushVO::getUpdatedTime,Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.toList());
		return page.setRecords(collect);
	}

	@Override
	public SccAlarmPushVO getData(String id) {
		log.info("==============获取警情详情开始==============");
		SccAlarmPush sccAlarmPush = this.getById(id);
		SccAlarmPushVO sccAlarmPushVO = Func.copy(sccAlarmPush, SccAlarmPushVO.class);
		sccAlarmPushVO.setReceiveDeptName(Func.isNotEmpty(sccAlarmPush.getReceiveDept()) ? departmentService.getById(sccAlarmPush.getReceiveDept()).getDeptName() : null);
		//获取相关附件
		List<UploadVO> attachments= fileService.getAttachments(sccAlarmPush.getId(),sccAlarmPush.getGroupName());
		sccAlarmPushVO.setRelevantAttachments(attachments);
		log.info("==============获取警情详情结束==============");
		return sccAlarmPushVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveData(SccAlarmPushDTO sccAlarmPushDTO) {
		log.info("==============警情信息编辑/推送开始==============");
		SccAlarmPush alarmPush = Func.copy(sccAlarmPushDTO, SccAlarmPush.class);
		alarmPush.setDeptId(AuthUtil.getDeptId());
		alarmPush.setPushState(sccAlarmPushDTO.getSubmitType());
		alarmPush.setStatus(Constant.PUSH_STATUS_ZERO);
		if (Func.isEmpty(sccAlarmPushDTO.getDeptRoles())){
			setReceiveRoles(sccAlarmPushDTO.getReceiveDept(),alarmPush);
		}
		//将警情信息增值推送和编辑分开
		boolean b;
		if (Func.isNotEmpty(sccAlarmPushDTO.getId())){
			b = this.update(alarmPush,new UpdateWrapper<SccAlarmPush>().lambda().eq(SccAlarmPush::getId,sccAlarmPushDTO.getId()).eq(SccAlarmPush::getPushState,Constant.PUSH_STATE_ZERO));
		}else {
			b = this.save(alarmPush);
		}
		//保存相关附件
		if (b) {
			fileService.saveAttachments(sccAlarmPushDTO.getRelevantAttachments(),alarmPush.getId());
		}
		//如果页面操作为推送警情，则调用信息发送接口
		boolean result = true;
		if (Constant.SUBMIT_TYPE_ONE.equals(sccAlarmPushDTO.getSubmitType()) && "0".equals(sccAlarmPushDTO.getMenuType())){
			//result = startProcess(alarmPush);
			sendAlarmMsg(alarmPush);
		}
		log.info("==============警情信息编辑/推送结束==============");
		return result;
	}

	/**
	 *发送警情信息的香云通知
	 */
	private void sendAlarmMsg(SccAlarmPush alarmPush) {
		log.info("==============发送警情信息的香云通知开始==============");
		//获取消息通知人员工号
		List<String> userCodes = getNoticeUserCode(alarmPush);
		String msg = "您有一条["+ alarmPush.getAlarmTime() +"]时间推送，事件描述为[" + alarmPush.getEventDescription() + "]的警情信息待处理！";
		xYunClient.sendMessageToXYun(Func.join(userCodes,","),msg);
		log.info("==============发送警情信息的香云通知结束==============");
	}

	/**
	 * 获取消息通知人员工号
	 */
	private List<String> getNoticeUserCode(SccAlarmPush alarmPush) {
		List<String> userCodes = new ArrayList<>();
		//获取消息通知人员工号
		List<String> list = Arrays.asList(alarmPush.getDeptRoles().split(","));
		if (Func.isNotEmpty(list)){
			list.forEach(roleId ->{
				List<UserVO> user = inspectionService.getUserByRoleId(roleId, alarmPush.getReceiveDept());
				if (Func.isNotEmpty(user)){
					user.forEach(item->{
						userCodes.add(item.getCode());
					});
				}
			});
		}
		return userCodes;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean senAlarmNotice(SccAnswerAlarm sccAnswerAlarm) {
		SccAlarmPush alarmPush = setSccAlarmPush(sccAnswerAlarm);
		//获取联系接警记录附件
		List<UploadVO> attachments = fileService.getAttachments(sccAnswerAlarm.getId(), sccAnswerAlarm.getGroupName());
		this.save(alarmPush);
		//将附件保存至警情信息记录下
		if (Func.isNotEmpty(attachments)){
			attachments.forEach(item -> {
				item.setGroupName("aralmPushAttachments");
				item.setId(null);
			});
		}
		fileService.saveAttachments(attachments,alarmPush.getId());
		//发送警情信息香云通知
		sendAlarmMsg(alarmPush);
		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeData(List<String> toStrList) {
		return this.removeByIds(toStrList) && fileService.removeFileData(toStrList);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateData(SccAlarmPushDTO sccAlarmPushDTO) {
		SccAlarmPush alarmPush = Func.copy(sccAlarmPushDTO, SccAlarmPush.class);
		//将警情信暂存
		this.updateById(alarmPush);
		//保存相关附件
		fileService.saveAttachments(sccAlarmPushDTO.getRelevantAttachments(),alarmPush.getId());
		return true;
	}

	@Override
	public List<SccAlarmPush> getListData(String status) {
		return this.list(new QueryWrapper<SccAlarmPush>().lambda().eq(Func.isNotEmpty(status),SccAlarmPush::getStatus,status)
		.eq(SccAlarmPush::getDelFlag,Constant.DELETE_FLAG_0));
	}

	public boolean startProcess(SccAlarmPush alarmPush) {
		R<BladeFlowDef> definitionRes = flowClient.getLatestProcessDefinitionByKey(ProcessConstant.SCC_ALARM_PUSH_KEY);
		if (definitionRes.isSuccess()) {
			alarmPush.setProcessDefinitionId(definitionRes.getData().getId());
		} else {
			throw new ServiceException("开启流程失败");
		}
		R<Integer> deptCategory = sysClient.getDeptCategory(Long.valueOf(AuthUtil.getUser().getDeptId()));
		if (!deptCategory.isSuccess()) {
			throw new ServiceException("查询部门类型失败，请检查后再试！");
		}
		Integer sendDeptCategory;
		if (!Func.isNull(alarmPush) && !Func.isNull(alarmPush.getLinkId()) && !Func.isEmpty(alarmPush.getLinkId())) {
			SccAnswerAlarm sccAnswerAlarm = answerAlarmMapper.selectById(alarmPush.getLinkId());
			if (Func.isNull(sccAnswerAlarm) || Func.isNull(sccAnswerAlarm.getDeptId()) || Func.isEmpty(sccAnswerAlarm.getDeptId())) {
				throw new ServiceException("推送部门为空，请检查后再试！");
			}
			R<Integer> sendDeptCategoryRes = sysClient.getDeptCategory(Long.valueOf(sccAnswerAlarm.getDeptId()));
			if (!sendDeptCategoryRes.isSuccess()) {
				throw new ServiceException("查询推送部门类型失败，请检查后再试！");
			}
			sendDeptCategory = sendDeptCategoryRes.getData();
		} else {
			sendDeptCategory = deptCategory.getData();
		}
		Kv variables = Kv.create()
			.set(ProcessConstant.BUSINESS_ID_KEY, alarmPush.getId())
			.set("deptCategory", deptCategory.getData())
			.set("sendDeptCategory", sendDeptCategory)
			.set(ProcessConstant.START_PROC_USER_ID, AuthUtil.getUserId());
		String businessTable = FlowUtil.getBusinessTable(SccAlarmPush.class);
		R<BladeFlow> result = flowClient.startProcessInstanceById(alarmPush.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(alarmPush.getId())), variables);
		if (result.isSuccess()) {
			log.debug("流程已启动,流程ID:" + result.getData().getProcessInstanceId());
			alarmPush.setProcessInstanceId(result.getData().getProcessInstanceId());
		} else {
			throw new ServiceException("开启流程失败");
		}
		this.saveOrUpdate(alarmPush);
		return true;
	}

	/**
	 *封装警情推送信息
	 */
	private SccAlarmPush setSccAlarmPush(SccAnswerAlarm sccAnswerAlarm) {
		SccAlarmPush alarmPush = new SccAlarmPush();
		alarmPush.setLinkId(sccAnswerAlarm.getId());
		alarmPush.setAlarmType(sccAnswerAlarm.getAlarmType());
		alarmPush.setAlarmTime(sccAnswerAlarm.getAlarmTime());
		alarmPush.setEventDescription(sccAnswerAlarm.getCallContent());
		alarmPush.setReceiveDept(sccAnswerAlarm.getPlace());
		alarmPush.setPushState(Constant.PUSH_STATE_ONE);
		alarmPush.setStatus(Constant.PUSH_STATUS_ZERO);
		alarmPush.setReceiveDeptFront(sccAnswerAlarm.getPlaceCodeFront());
		String receiveDeptId = sccAnswerAlarm.getPlace();
		setReceiveRoles(receiveDeptId, alarmPush);
		alarmPush.setDeptId(AuthUtil.getDeptId());
		return alarmPush;
	}

	/**
	 *设置警情接收相关角色
	 */
	private void setReceiveRoles(String receiveDeptId, SccAlarmPush alarmPush) {
		log.info("==============获取警情接收相关角色开始==============");
		List<String> dutyPerson = baseMapper.getDutyPerson(receiveDeptId);
		alarmPush.setDeptRoles(Func.isNotEmpty(dutyPerson) ?  Func.join(dutyPerson,","): "");
		log.info("==============获取警情接收相关角色结束==============");
	}

}
