package com.casic.missiles.service.Impl.equipment;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.core.base.service.IBaseExportService;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.BaseApprovalSubmitRequest;
import com.casic.missiles.dto.IdDTO;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.equipment.EquipmentApplyProcessRequest;
import com.casic.missiles.dto.equipment.EquipmentApplyRequest;
import com.casic.missiles.dto.equipment.StateManageResponse;
import com.casic.missiles.dto.flowable.AllApproveDTO;
import com.casic.missiles.dto.flowable.ApprovalDeleteRequest;
import com.casic.missiles.dto.flowable.ToBeApprovedDTO;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.enums.ExportEnum;
import com.casic.missiles.enums.equipment.EquipmentApplyProcessEnum;
import com.casic.missiles.enums.equipment.EquipmentApplyTypeEnum;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.equipment.EquipmentApplyEquipmentMapper;
import com.casic.missiles.mapper.equipment.EquipmentApplyMapper;
import com.casic.missiles.mapper.equipment.EquipmentUseLogMapper;
import com.casic.missiles.model.equipment.*;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.equipment.IEquipmentApplyEquipmentService;
import com.casic.missiles.service.equipment.IEquipmentApplyFileService;
import com.casic.missiles.service.equipment.IEquipmentApplyService;
import com.casic.missiles.service.equipment.IEquipmentUseLogService;
import com.casic.missiles.service.flowable.ApprovalOperateService;
import com.casic.missiles.utils.DictCodeUtils;
import com.casic.missiles.utils.NumberGeneratorUtil;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@Service("IEquipmentApplyService")
public class EquipmentApplyServiceImpl extends ServiceImpl<EquipmentApplyMapper, EquipmentApply> implements IEquipmentApplyService {

    @Resource
    private EquipmentApplyMapper equipmentApplyMapper;

    @Resource
    private EquipmentApplyEquipmentMapper equipmentMapper;

    @Resource
    private IEquipmentApplyEquipmentService equipmentService;

    @Resource
    private IEquipmentApplyFileService applyFileService;

    @Resource
    private IBaseExportService iBaseExportService;

    @Resource
    private IBaseApprovalService baseApprovalService;

    @Resource
    private ApprovalOperateService approvalOperateService;

    @Resource
    private TaskService taskService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private IEquipmentUseLogService iEquipmentUseLogService;

    @Resource
    private EquipmentUseLogMapper equipmentUseLogMapper;


    @Override
    public Page<EquipmentApply> equipmentApplyList(Page<EquipmentApply> page, EquipmentApplyRequest request) throws Exception {
        List<String> businessKeys = new ArrayList<>();
        boolean searchBusinessKey = true;
        String status = request.getApprovalStatus();
        Map<String,String> taskMap = new HashMap<>(); // businessKey-taskId, 待审批列表用
        Map<String,Integer> decisionItemMap = new HashMap<>(); // 可选决策项map
        List<String> rejectBusinessKey = new ArrayList<>();// 未通过-驳回
        switch (status){
            case ApprovalStatusEnum.TO_BE_APPROVED:
                List<ToBeApprovedDTO> toBeApprovedList = baseApprovalService.getToBeApprovedList(request.getFormId());
                businessKeys = toBeApprovedList.stream().map(ToBeApprovedDTO::getBusinessKey).distinct().collect(Collectors.toList());
                toBeApprovedList.forEach(toBeApprovedDTO -> {taskMap.put(toBeApprovedDTO.getBusinessKey(),toBeApprovedDTO.getTaskId());});
                toBeApprovedList.forEach(toBeApprovedDTO -> {decisionItemMap.put(toBeApprovedDTO.getBusinessKey(),toBeApprovedDTO.getDecisionItem());});
                break;
            case ApprovalStatusEnum.IN_APPROVED:
                businessKeys = baseApprovalService.getInApprovedList(request.getFormId());
                break;
            case ApprovalStatusEnum.PASSED:
                businessKeys = baseApprovalService.getPassedList(request.getFormId());
                break;
            case ApprovalStatusEnum.FAILED:
                businessKeys = baseApprovalService.getFailedList(request.getFormId());
                rejectBusinessKey = baseApprovalService.getFailedRejectList(request.getFormId()); //未通过-驳回
                businessKeys.addAll(rejectBusinessKey);
                break;
            case ApprovalStatusEnum.CANCELED:
                businessKeys = baseApprovalService.getCanceledList(request.getFormId());
                break;
            case ApprovalStatusEnum.ALL:
                List<AllApproveDTO> allList = baseApprovalService.getAllList(request.getFormId());
                businessKeys = allList.stream().map(AllApproveDTO::getBusinessKey).distinct().collect(Collectors.toList());
                allList.forEach(allApprovedDTO -> {taskMap.put(allApprovedDTO.getBusinessKey(),allApprovedDTO.getStatus());});
                break;
            default:
                // 草稿箱，直接查表，不用查工作流
                searchBusinessKey = false;
                break;
        }

        if(searchBusinessKey){
            if(CollectionUtils.isEmpty(businessKeys)){
                return page;
            }else {
                request.setApprovalStatus(null);
                request.setBusinessKeys(businessKeys);
            }
        }

        Page<EquipmentApply> resultPage = equipmentApplyMapper.equipmentApplyList(page, request);
        for (EquipmentApply equipmentApply : resultPage.getRecords()) {
            if(searchBusinessKey){
                equipmentApply.setApprovalStatus(status);
                // 未通过-驳回状态
                if(status.equals(ApprovalStatusEnum.FAILED) && rejectBusinessKey.contains(equipmentApply.getId().toString())){
                    equipmentApply.setApprovalStatus(ApprovalStatusEnum.FAILED_REJECT);
                }
            }
            if(ApprovalStatusEnum.TO_BE_APPROVED.equals(status)){
                equipmentApply.setTaskId(taskMap.get(equipmentApply.getId().toString()));
                equipmentApply.setDecisionItem(decisionItemMap.get(equipmentApply.getId().toString()));
            }
            if(ApprovalStatusEnum.ALL.equals(status)){
                equipmentApply.setApprovalStatus(taskMap.get(String.valueOf(equipmentApply.getId())));
            }
            DictCodeUtils.convertDictCodeToName(equipmentApply);
        }
        return resultPage;
    }

    @Override
    public Object equipmentApplyInfo(IdDTO idDTO)  throws Exception{
        // 通过id查询申请基本信息
        EquipmentApply equipmentApply = equipmentApplyMapper.equipmentApplyInfo(idDTO.getId());
        // 替换字典值
        DictCodeUtils.convertDictCodeToName(equipmentApply);
        // 查询设备详细信息
        List<EquipmentFixedAssets> fixedAssetsList = equipmentMapper.queryEquipmentList(idDTO.getId());
        for (EquipmentFixedAssets equipmentFixedAssets : fixedAssetsList) {
            DictCodeUtils.convertDictCodeToName(equipmentFixedAssets);
        }
        equipmentApply.setEquipmentInfoList(fixedAssetsList);
        return equipmentApply;
    }

    @Override
    @Transactional
    public ReturnDTO addEquipmentApply(EquipmentApply equipmentApply) {
        Long maxNo = equipmentApplyMapper.selectMaxNo();
        // 生成编号
        String applyNo = NumberGeneratorUtil.getContactNo(getApplyNoPrefix(equipmentApply.getApplyType()), maxNo);
        equipmentApply.setApplyNo(applyNo);
        // 草稿箱状态
        equipmentApply.setApprovalStatus(ApprovalStatusEnum.DRAFT);
        if(StringUtils.isEmpty(equipmentApply.getCreateUser()) && ShiroKit.getUser() != null){
            equipmentApply.setCreateUser(ShiroKit.getUser().getId().toString());
        }
        if(equipmentApplyMapper.insert(equipmentApply) > 0){
            Long id = equipmentApply.getId();
            for (EquipmentApplyEquipment applyEquipment : equipmentApply.getEquipmentList()) {
                applyEquipment.setApplyId(id.toString());
            }
            boolean equipmentSaveBatchFlg = true;
            // 新增设备信息
            if(!CollectionUtils.isEmpty(equipmentApply.getEquipmentList())){
                equipmentSaveBatchFlg = equipmentService.saveBatch(equipmentApply.getEquipmentList());
            }
            boolean saveBatchFlg = true;
            // 新增附件列表
            if(!CollectionUtils.isEmpty(equipmentApply.getFileList())){
                for (EquipmentApplyFile file : equipmentApply.getFileList()) {
                    file.setApplyId(id);
                }
                saveBatchFlg = applyFileService.saveBatch(equipmentApply.getFileList());
            }
            if(equipmentSaveBatchFlg && saveBatchFlg){
                return ReturnUtil.success(id);
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    private String getApplyNoPrefix(String applyType){
        switch (applyType){
            case EquipmentApplyTypeEnum.REQUIRE_APPLY:
                return "sblysq";
            case EquipmentApplyTypeEnum.BORROW_APPLY:
                return "sbjysq";
            case EquipmentApplyTypeEnum.IDEL_APPLY:
                return "sbxzsq";
            case EquipmentApplyTypeEnum.SEAL_APPLY:
                return "sbfcsq";
            case EquipmentApplyTypeEnum.UNSEAL_APPLY:
                return "sbqfsq";
            case EquipmentApplyTypeEnum.SCRAP_APPLY:
                return "sbbfsq";
            case EquipmentApplyTypeEnum.HANDLE_APPLY:
                return "sbczsq";
            case EquipmentApplyTypeEnum.EXAM_APPLY:
                return "sbjx";
            case EquipmentApplyTypeEnum.REPAIR_APPLY:
                return "sbjxbyysd";
            default:
                return "";
        }
    }

    @Override
    @Transactional
    public ReturnDTO deleteEquipmentApply(ApprovalDeleteRequest request) {
        int flag = 0;
        // 审批操作-删除
        if(StringUtils.isNotEmpty(request.getTaskId())){
            // 删除表单对应流程实例
            ReturnDTO returnDTO = approvalOperateService.delete(request);
            if(ResponseData.DEFAULT_SUCCESS_CODE == returnDTO.getCode()){
                //本地删除
                flag = equipmentApplyMapper.deleteById(request.getId());
            }
        }else{
            // 草稿箱等非审批操作删除
            flag = equipmentApplyMapper.deleteById(request.getId());
        }
        if(flag>0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO updateEquipmentApply(EquipmentApply equipmentApply) {
        // 修改申请基本信息
        int updateFlg = equipmentApplyMapper.updateById(equipmentApply);
        if(updateFlg>0){
            // 删除所有关联设备信息
            QueryWrapper<EquipmentApplyEquipment> wrapper = new QueryWrapper<>();
            wrapper.eq("apply_id",equipmentApply.getId());
            equipmentService.remove(wrapper);
            for (EquipmentApplyEquipment equipment : equipmentApply.getEquipmentList()) {
                equipment.setApplyId(equipmentApply.getId().toString());
            }
            // 新增最终确定的设备list
            if(equipmentService.saveBatch(equipmentApply.getEquipmentList())){
                return ReturnUtil.success();
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public void exportList(EquipmentApplyRequest request, HttpServletResponse response) throws Exception {
        List<EquipmentApply> resultList;

        // 判断是否为通过ids导出
        if(!CollectionUtils.isEmpty(request.getIds())){
            EquipmentApplyRequest applyRequest = new EquipmentApplyRequest();
            applyRequest.setIds(request.getIds());
            resultList = equipmentApplyMapper.equipmentApplyList(applyRequest);
        }else{
            request.setBusinessKeys(EquipmentStateManageServiceImpl.getBusinessKeys(request.getApprovalStatus(), request.getFormId(),baseApprovalService));
            if(!request.getApprovalStatus().equals(ApprovalStatusEnum.DRAFT)){
                request.setApprovalStatus(null);
            }
            resultList = equipmentApplyMapper.equipmentApplyList(request);
        }
        for (EquipmentApply equipmentApply : resultList) {
            DictCodeUtils.convertDictCodeToName(equipmentApply);
        }
        iBaseExportService.exportExcel(response, EquipmentApply.class,resultList, ExportEnum.EQUIPMENT_APPLY.getSheetName());
    }

    @Override
    @Transactional
    public ReturnDTO borrowEquipmentApply(IdDTO idDto) {
        UpdateWrapper<EquipmentApply> updateWrapper = new UpdateWrapper<>();
        // 通过id修改处理结果
        updateWrapper.eq("id",idDto.getId()).set("process_result", EquipmentApplyProcessEnum.ALREADY_BORROWED);
        if(equipmentApplyMapper.update(null, updateWrapper)>0){
            // 新增设备使用记录表
            this.addEquipmentUseLog(idDto.getId(),EquipmentApplyProcessEnum.BORROWED);
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO returnEquipmentApply(IdDTO idDto) {
        UpdateWrapper<EquipmentApply> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",idDto.getId()).set("process_result", EquipmentApplyProcessEnum.ALREADY_RETURN).set("back_time",new Date());
        if(equipmentApplyMapper.update(null, updateWrapper)>0){
            // 修改设备使用记录表
            this.updateEquipmentUseLog(idDto.getId());
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO updateProcessResult(EquipmentApplyProcessRequest request) {
        UpdateWrapper<EquipmentApply> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",request.getId()).set("process_result", request.getProcessResult());
        if(equipmentApplyMapper.update(null, updateWrapper)>0){
            if(request.getProcessResult().equals(EquipmentApplyProcessEnum.ALREADY_COLLECTING)){
                // 领用新增使用记录
                this.addEquipmentUseLog(request.getId(),EquipmentApplyProcessEnum.COLLECT);
            }else{
                // 退领修改使用记录
                this.updateEquipmentUseLog(request.getId());
            }
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO submitEquipmentApply(BaseApprovalSubmitRequest request) {
        //已取消后的提交需先删除原有实例
        if (StringUtils.isNotEmpty(request.getProcessId())){
            runtimeService.updateBusinessStatus(request.getProcessId(), ApprovalStatusEnum.DELETED);
            runtimeService.deleteProcessInstance(request.getProcessId(), "删除");
        }
        String formId = request.getFormId();
        // 发起流程
        ReturnDTO returnDTO = baseApprovalService.processSubmit(formId, request.getId());
        if(ResponseData.DEFAULT_SUCCESS_CODE != returnDTO.getCode()){
            return returnDTO;
        }
        ProcessInstance processInstance = (ProcessInstance)returnDTO.getData();
        // 通过id查出当前表单
        EquipmentApply equipmentApply = this.baseMapper.selectById(request.getId());
        // 设置审批状态
        equipmentApply.setApprovalStatus(ApprovalStatusEnum.UN_DRAFT); //非草稿状态
        // 存储流程实例id
        equipmentApply.setProcessId(processInstance.getId());
        int row = this.baseMapper.updateById(equipmentApply);
        if (row <= 0) {
            throw new BusinessException(BusinessExceptionEnum.TRACE_SUPPLIER_SUBMIT_FAILED.getCode(), BusinessExceptionEnum.TRACE_SUPPLIER_SUBMIT_FAILED.getMessage());
        }
        return ReturnUtil.success();
    }

    @Override
    @Transactional
    public ReturnDTO failUpdate(EquipmentApply equipmentApply) {
        // 修改申请基本信息
        int updateFlg = equipmentApplyMapper.updateById(equipmentApply);
        if(updateFlg>0){
            // 删除所有关联设备信息
            QueryWrapper<EquipmentApplyEquipment> wrapper = new QueryWrapper<>();
            wrapper.eq("apply_id",equipmentApply.getId());
            equipmentService.remove(wrapper);
            equipmentApply.getEquipmentList().forEach(bean->{
                bean.setApplyId(equipmentApply.getId().toString());
            });
            // 新增最终确定的设备list
            if(equipmentService.saveBatch(equipmentApply.getEquipmentList())){
                baseApprovalService.failUpdate(equipmentApply.getProcessId());
                return ReturnUtil.success();
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }
    private void addEquipmentUseLog(Long applyId,String useType) {
        // 通过id查申请信息
        EquipmentApply apply = equipmentApplyMapper.selectById(applyId);
        // 通过id查对应设备
        QueryWrapper<EquipmentApplyEquipment> wrapper = new QueryWrapper<>();
        wrapper.eq("apply_id",applyId);
        List<EquipmentApplyEquipment> equipmentApplyEquipments = equipmentMapper.selectList(wrapper);
        List<EquipmentUseLog> logList = new ArrayList<>();
        for (EquipmentApplyEquipment equipment : equipmentApplyEquipments) {
            EquipmentUseLog useLog = new EquipmentUseLog(applyId,Long.parseLong(equipment.getEquipmentId()),apply.getApplyUnit(),apply.getApplyPerson(),useType, DateUtils.format(new Date()),null);
            logList.add(useLog);
        }
        if(!iEquipmentUseLogService.saveBatch(logList)){
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
    }
    private void updateEquipmentUseLog(Long applyId){
        QueryWrapper<EquipmentApplyEquipment> wrapper = new QueryWrapper<>();
        wrapper.eq("apply_id",applyId);
        List<EquipmentApplyEquipment> equipmentApplyEquipments = equipmentMapper.selectList(wrapper);
        List<String> ids = equipmentApplyEquipments.stream().map(EquipmentApplyEquipment::getEquipmentId).collect(Collectors.toList());
        UpdateWrapper<EquipmentUseLog> updateWrapper = new UpdateWrapper<>();
        // 通过id修改处理结果
        updateWrapper.eq("apply_id",applyId).in("equipment_id",ids).isNull("end_date").set("end_date", DateUtils.format(new Date()));
        if(equipmentUseLogMapper.update(null,updateWrapper)<=0){
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
    }
}
