/*
 *      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.dailyDuties.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.security.common.Constant;
import org.security.common.util.DataFormatUtil;
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.app.vo.BacklogVO;
import org.security.ht.entity.basic.Department;
import org.security.trans.basic.service.IDepartmentService;
import org.security.trans.dailyDuties.dto.InspectionDTO;
import org.security.trans.dailyDuties.entity.Inspection;
import org.security.trans.dailyDuties.entity.InspectionLine;
import org.security.trans.dailyDuties.mapper.InspectionMapper;
import org.security.trans.dailyDuties.service.IInspectionLineService;
import org.security.trans.dailyDuties.service.IInspectionService;
import org.security.trans.dailyDuties.vo.InspectionVO;
import org.security.trans.dataStatistics.dto.InspectionDataDTO;
import org.security.trans.dataStatistics.vo.InspectionDataVO;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.BladeUser;
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 org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static org.security.common.Constant.*;

/**
 * 任务-监督检查表 服务实现类
 *
 * @author BladeX
 * @since 2022-03-25
 */
@Slf4j
@Service
@AllArgsConstructor
public class InspectionServiceImpl extends ServiceImpl<InspectionMapper, Inspection> implements IInspectionService {
	private final IInspectionLineService inspectionLineService;
	private final IDepartmentService departmentService;
	private final IFlowClient flowClient;
	private final ISysClient sysClient;

	@Override
	public IPage<InspectionVO> selectInspectionPage(IPage<InspectionVO> page, InspectionDTO inspectionDTO) {
		//获取模块标识符List
		List<String> businessTypeList = Func.toStrList(inspectionDTO.getBizTypeStr());
		List<InspectionVO> vos = baseMapper.selectInspectionPage(page, inspectionDTO, businessTypeList);
		//根据机构id和用户id获取对应name值
		vos.forEach(this::setReturnResult);
		return page.setRecords(vos);
	}

	/**
	 * 处理返回对象，根据id获取对应name值
	 */
	private void setReturnResult(InspectionVO item) {
		//提报机构
		if (Func.isNotEmpty(item.getDeptId())) {
			item.setDeptName(departmentService.getById(item.getDeptId()).getDeptName());
		}
		//检查机构
		if (INSPECTION_TYPE_OUT.equals(item.getCheckType())) {
			//检查机构为外部机构，直接赋值
			item.setInspectDepName(item.getInspectDep());
		}else if(!(INSPECTION_TYPE_OUT.equals(item.getCheckType()))){
			//检查机构为内部机构，从机构表里查出机构名
			item.setInspectDepName(departmentService.getById(item.getInspectDep()).getDeptName());
		}
		//被检查机构
		item.setInspectedDepName(departmentService.getById(item.getInspectedDep()).getDeptName());
		//整改责任人
		if (Func.isNotEmpty(item.getRectifyUser())) {
			item.setRectifyUserName(baseMapper.getUserName(item.getRectifyUser()));
		}
		//关联任务
		if (Func.isNotEmpty(item.getTaskId())) {
			item.setTaskName(baseMapper.getTaskData(item.getTaskId()));
		}
	}

	/**
	 * 提交整改结果
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R changeStateById(String id) throws ParseException {
		log.info("==============[提交整改结果]开始==============");
		Inspection inspection = this.getById(id);
		//发起审批流程
		R<BladeFlowDef> definitionRes = flowClient.getLatestProcessDefinitionByKey(ProcessConstant.INSPECTION_KEY);
		if (definitionRes.isSuccess()) {
			inspection.setProcessDefinitionId(definitionRes.getData().getId());
		} else {
			throw new ServiceException("开启流程失败");
		}
		R<Integer> deptCategory = sysClient.getDeptCategory(Long.valueOf(AuthUtil.getUser().getDeptId()));
		if (!deptCategory.isSuccess()) {
			throw new ServiceException("查询部门类型失败，请检查后再试！");
		}
		String businessTable = FlowUtil.getBusinessTable(Inspection.class);
		Kv variables = Kv.create()
			.set("deptCategory", deptCategory.getData())
			.set(ProcessConstant.BUSINESS_ID_KEY, inspection.getId())
			.set(ProcessConstant.START_PROC_USER_ID, AuthUtil.getUserId());
		R<BladeFlow> result = flowClient.startProcessInstanceById(inspection.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(inspection.getId())), variables);
		if (result.isSuccess()) {
			//	业务状态：根据整改期限及当前日期判断是否超时整改
			inspection.setState(inspection.getRectifyDeadline().before(DataFormatUtil.getLocalDate()) ? PROBLEM_STATE_OVERTIME_SUBMIT : PROBLEM_STATE_SUBMIT);
			inspection.setStatus(HANDIN_STATE_AUDIT);//流程状态 -审批中
			inspection.setRectifyStatus("1");//整改是否完成 1-是
			inspection.setProcessInstanceId(result.getData().getProcessInstanceId());
		}else{
			return R.fail(400,"开启流程失败");
		}
		this.updateById(inspection);
		log.info("==============[提交整改结果]结束==============");
		return R.success("提交成功");
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean removeInspectionAndLineByIds(List<Long> toLongList) {
		return this.removeByIds(toLongList) && inspectionLineService.removeData(toLongList);
	}

	/**
	 * 查询表单详情
	 */
	@Override
	public InspectionVO getInspectionData(String id) {
		//获取监督检查主表信息
		Inspection inspection = super.getById(id);
		InspectionVO inspectionVO = Func.copy(inspection, InspectionVO.class);
		setReturnResult(inspectionVO);
		//获取检查部门idList
		getInspectDept(inspection, inspectionVO);
		//获取被检查部门idList
		getInspectedDept(inspection, inspectionVO);
		//获取明细信息
		List<InspectionLine> lineList = inspectionLineService.list(new QueryWrapper<InspectionLine>().eq("FORM_ID", id));
		if (Func.isNotEmpty(lineList)) {
			inspectionVO.setInspectionLineVOList(lineList);
		}
		return inspectionVO;
	}

	/**
	 * 获取检查部门idList
	 */
	private void getInspectDept(Inspection inspection, InspectionVO inspectionVO) {
		if (!(INSPECTION_TYPE_OUT.equals(inspection.getCheckType()))) {
			Department inspectDepId = departmentService.getById(inspection.getInspectDep());
			if (Func.isNotEmpty(inspectDepId)) {
				//检查部门为红塔银行
				if (PARENT_ID.equals(String.valueOf(inspectDepId.getParentId()))) {
					ArrayList<String> list = new ArrayList<>();
					list.add(String.valueOf(inspectDepId.getId()));
					inspectionVO.setOrgOptions(list);
				} else {
					List<String> list = Arrays.stream(inspectDepId.getAncestors().split(",")).collect(Collectors.toList());
					list.remove(0);
					list.add(inspection.getInspectDep());
					inspectionVO.setOrgOptions(list);
				}
			}
		}
	}

	/**
	 * 获取被检查部门idList
	 */
	private void getInspectedDept(Inspection inspection, InspectionVO inspectionVO) {
		Department inspectedDepId = departmentService.getById(inspection.getInspectedDep());
		if (Func.isNotEmpty(inspectedDepId)) {
			//被检查部门为红塔银行
			if (PARENT_ID.equals(String.valueOf(inspectedDepId.getParentId()))) {
				ArrayList<String> list = new ArrayList<>();
				list.add(String.valueOf(inspectedDepId.getId()));
				inspectionVO.setOptions(list);
			} else {
				List<String> list = Arrays.stream(inspectedDepId.getAncestors().split(",")).collect(Collectors.toList());
				list.remove(0);
				list.add(inspection.getInspectedDep());
				inspectionVO.setOptions(list);
			}
		}
	}

	@Override
	public Inspection getCheckInspection(String taskId, String deptId, Date creatStartDate, Date creatEndDate) {
		QueryWrapper<Inspection> wrapper = new QueryWrapper<>();
		wrapper.eq("TASK_ID", taskId);
		wrapper.eq("INSPECTED_DEP", deptId);
		wrapper.ge("CREATED_TIME", creatStartDate);
		wrapper.le("CREATED_TIME", creatEndDate);
//		wrapper.eq("status","0");
		return baseMapper.selectOne(wrapper);
	}

	@Override
	public List<Inspection> getCheckList(String status) {
		QueryWrapper<Inspection> wrapper = new QueryWrapper<>();
		wrapper.eq("STATUS", status);
		return baseMapper.selectList(wrapper);
	}

	/**
	 * 新增或更新（暂存）检查表
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R saveOrUpdateInspection(InspectionDTO inspectionDto) {
		if(Func.isEmpty(inspectionDto.getUserId())){
			inspectionDto.setUserId(String.valueOf(AuthUtil.getUserId()));
		}
		Inspection inspection = Func.copy(inspectionDto, Inspection.class);
		//更新主表数据
		super.saveOrUpdate(inspection);
		List<InspectionLine> inspectionLineList = inspectionDto.getInspectionLineList();
		if (Func.isNotEmpty(inspectionLineList)) {
			inspectionLineList.forEach(item -> {
				item.setFormId(inspection.getId());
				//明细若有单独设置整改期限，则取明细的整改期限；若无，则取主表的整改期限
				item.setRectifyDeadline(Func.isNull(item.getRectifyDeadline())?inspection.getRectifyDeadline():item.getRectifyDeadline());
				item.setDeptId(inspection.getInspectedDep());//明细的提报机构为主表的被检查机构
				item.setUserId(inspection.getRectifyUser());//整改责任人
				item.setFoundDate(inspection.getInspectDate());//检查日期
				item.setFlag(Constant.PROBLEM_STATE_USUUAL); //明细类型默认为普通一次性整改
				item.setState(HANDIN_STATE_DRAFT);//审批状态 未提交审批
				item.setStatus("1".equals(item.getHasProblem())?PROBLEM_STATE_DRAFT:PROBLEM_STATE_NO_PROBLEM);//业务状态：无异常-6，有异常则置为0-待检查
				item.setFormStatus(inspection.getStatus());
			});
			//更新明细表数据
			inspectionLineService.saveOrUpdateBatch(inspectionLineList);
		}
		return R.data(inspection);
	}

	/**
	 * 提交检查表
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R handin(InspectionDTO inspectionDto) {
		log.info("==============inspection提交检查结果 开始==============");
		R<Inspection> res = saveOrUpdateInspection(inspectionDto);
		//明细中检查有异常的项
		List<InspectionLine> collect = inspectionDto.getInspectionLineList().stream().filter(item -> "1".equals(item.getHasProblem())).collect(Collectors.toList());
		//保存后的主表信息
		Inspection inspection = res.getData();
		inspection.setStatus(PROBLEM_STATE_WAIT_RECTIFY);//业务状态为已提交待整改
		// 若明细无异常项，主表可挂载审批流
		if (Func.isEmpty(collect)) {
			log.info("==============明细无异常项==============");
//			挂载审批流
			R<BladeFlowDef> definitionRes = flowClient.getLatestProcessDefinitionByKey(ProcessConstant.INSPECTION_KEY);
			if (definitionRes.isSuccess()) {
				inspection.setProcessDefinitionId(definitionRes.getData().getId());
			} else {
				return R.fail(400,"开启流程失败");
			}
			R<Integer> deptCategory = sysClient.getDeptCategory(Long.valueOf(AuthUtil.getUser().getDeptId()));
			if (!deptCategory.isSuccess()) {
				throw new ServiceException("查询部门类型失败，请检查后再试！");
			}
			String businessTable = FlowUtil.getBusinessTable(Inspection.class);
			String checkType;
			switch (inspection.getCheckType()) {
				case "1": case "2":
					checkType = "inside";
					break;
				case "3":
					checkType = "outside";
					break;
				default:
					throw new ServiceException("不支持的检查类型，请核对后再试！");
			}
			Kv variables = Kv.create()
				.set("deptCategory", deptCategory.getData())
				.set(ProcessConstant.BUSINESS_ID_KEY, inspection.getId())
				.set("checkType", checkType)
				.set(ProcessConstant.START_PROC_USER_ID, AuthUtil.getUserId());
			R<BladeFlow> result = flowClient.startProcessInstanceById(inspection.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(inspection.getId())), variables);
			if (result.isSuccess()) {
				inspection.setProcessInstanceId(result.getData().getProcessInstanceId());
				inspection.setStatus(PROBLEM_STATE_NO_PROBLEM);//业务状态为正常无需整改
				inspection.setState(HANDIN_STATE_AUDIT);//流程状态为进入审批
				inspection.setCheckStatus("0");//是否有异常 0-否
				inspection.setRectifyStatus("");//是否整改完成 置空
			} else {
				return R.fail(400, "开启流程失败");
			}
		}
//		若明细中有异常项，异常项状态改为待整改
		else if(Func.isNotEmpty(collect)){
			collect.forEach(item -> {
				item.setStatus(PROBLEM_STATE_WAIT_RECTIFY);
			});
			//更新明细表数据
			inspectionLineService.saveOrUpdateBatch(collect);
		}
		//更新主表数据
//		this.update(inspection, new UpdateWrapper<Inspection>().lambda().eq(Func.isNotEmpty(inspection.getId()), Inspection::getId, inspection.getId())
//			.eq(Inspection::getState, PROBLEM_STATE_DRAFT));
		super.saveOrUpdate(inspection);
		log.info("==============inspection提交检查结果 结束==============");
		return R.success("提交成功");
	}

	@Override
	public List<BacklogVO> getAppBacklog(BladeUser user) {
		return baseMapper.getAppBacklog(String.valueOf(user.getUserId()), PROBLEM_STATE_WAIT_RECTIFY);
	}

	@Override
	public List<UserVO> getUserByRoleId(String roleId,String deptId) {
		return baseMapper.getUserByRoleId(roleId,deptId);
	}

	@Override
	public String getDeptData(String deptId) {
		return baseMapper.getDeptData(deptId);
	}

	@Override
	public List<InspectionDataVO> getStatisticsData(InspectionDataDTO inspectionDataDTO, List<String> aimDepts) {
		return baseMapper.getStatisticsData(inspectionDataDTO,aimDepts);
	}
}
