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

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.model.auth.AuthUser;
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.StandardEquipmentApplyRequest;
import com.casic.missiles.dto.equipment.StandardEquipmentRequest;
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.StandardApplyTypeEnum;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.MeterFixedAssetsMapper;
import com.casic.missiles.mapper.equipment.*;
import com.casic.missiles.model.equipment.*;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.modular.system.dao.DeptMapper;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.equipment.IEquipmentStandardApplyEquipmentService;
import com.casic.missiles.service.equipment.IEquipmentStandardApplyFileService;
import com.casic.missiles.service.equipment.IEquipmentStandardApplyService;
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;

/**
 *
 * @author xiezhuangz
 * @version 1.0
 * @date 2022/12/19
 */
@Service("IEquipmentStandardApplyService")
public class EquipmentStandardApplyServiceImpl extends ServiceImpl<EquipmentStandardApplyMapper, EquipmentStandardApply> implements IEquipmentStandardApplyService {


    @Resource
    private EquipmentStandardApplyMapper meterStandardApplyMapper;

    @Resource
    private EquipmentStandardApplyEquipmentMapper standardApplyEquipmentMapper;

    @Resource
    private MeterFixedAssetsMapper meterFixedAssetsMapper;

    @Resource
    private EquipmentStandardApplyFileMapper standardApplyFileMapper;

    @Resource
    private EquipmentStandardEquipmentMapper meterStandardEquipmentMapper;

    @Resource
    private IEquipmentStandardApplyFileService meterStandardApplyFileService;

    @Resource
    private IEquipmentStandardApplyEquipmentService standardApplyEquipmentService;

    @Resource
    private EquipmentStandardSupportMapper standardSupportMapper;

    @Resource
    private IBaseExportService iBaseExportService;

    @Resource
    private IBaseApprovalService baseApprovalService;

    @Resource
    private ApprovalOperateService approvalOperateService;

    @Resource
    private RuntimeService runtimeService;

    @Override
    public Page<EquipmentStandardApply> standardEquipmentApplyList(Page<EquipmentStandardApply> page, StandardEquipmentApplyRequest request) throws Exception {
        Page<EquipmentStandardApply> resultPage;
        List<String> businessKeys = new ArrayList<>();
        boolean searchBusinessKey = true;
        String status = request.getApprovalStatus();
        List<String> rejectBusinessKey = new ArrayList<>();// 未通过-驳回
        Map<String,String> taskMap = new HashMap<>(); // businessKey-taskId, 待审批列表用
        Map<String,Integer> decisionItemMap = new HashMap<>(); // 可选决策项map
        switch (request.getApprovalStatus()){
            case ApprovalStatusEnum.TO_BE_APPROVED:
                List<ToBeApprovedDTO> toBeApprovedList = baseApprovalService.getToBeApprovedList(request.getFormId());
                if(ObjectUtil.isNotEmpty(toBeApprovedList)){
                    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){
            request.setApprovalStatus(null);
            if(!CollectionUtils.isEmpty(businessKeys)){
                request.setBusinessKeys(businessKeys);
            }else{
                return page;
            }
        }
        resultPage = meterStandardApplyMapper.standardEquipmentList(page, request);
        for (EquipmentStandardApply item: resultPage.getRecords()) {
            if(searchBusinessKey){
                item.setApprovalStatus(status);
                // 未通过-驳回状态
                if(status.equals(ApprovalStatusEnum.FAILED) && rejectBusinessKey.contains(item.getId().toString())){
                    item.setApprovalStatus(ApprovalStatusEnum.FAILED_REJECT);
                }
            }
            if(ApprovalStatusEnum.TO_BE_APPROVED.equals(status)){
                item.setTaskId(taskMap.get(item.getId().toString()));
                item.setDecisionItem(decisionItemMap.get(item.getId().toString()));
            }
            if(ApprovalStatusEnum.ALL.equals(status)){
                item.setApprovalStatus(taskMap.get(String.valueOf(item.getId())));
            }
            DictCodeUtils.convertDictCodeToName(item);
        }
        return resultPage;
    }

    @Override
    public Object standardEquipmentApplyInfo(IdDTO idDTO) throws Exception {
        // 通过id获取申请记录
        EquipmentStandardApply result = meterStandardApplyMapper.selectApplyInfo(idDTO.getId());
        // 通过申请标准装置id获取标准装置详细信息
        StandardEquipmentRequest request = new StandardEquipmentRequest();
        request.setId(Long.parseLong(result.getStandardEquipmentId()));
        EquipmentStandardEquipment standardEquipment = meterStandardEquipmentMapper.listPage(request);
        if(ObjectUtil.isEmpty(standardEquipment)){
            throw new BusinessException(BusinessExceptionEnum.STANDARD_EQUIPMENT_ID_EXIST);
        }
        DictCodeUtils.convertDictCodeToName(standardEquipment);
        result.setMeterStandardEquipment(standardEquipment);
        if(result.getApplyType().equals(StandardApplyTypeEnum.REPLACE_APPLY)){
            QueryWrapper<EquipmentStandardApplyEquipment> wrapper = new QueryWrapper<>();
            wrapper.eq("standard_apply_id",result.getId());
            // 通过申请id查询对应设备表
            List<EquipmentStandardApplyEquipment> meterStandardApplyEquipments = standardApplyEquipmentMapper.selectList(wrapper);
            List<Long> equipmentIds = meterStandardApplyEquipments.stream().map(EquipmentStandardApplyEquipment::getEquipmentId).collect(Collectors.toList());
            // 通过对应设备id查询设备详细信息
            if(!CollectionUtils.isEmpty(equipmentIds) && equipmentIds.size()!=0){
                List<EquipmentStandardSupportEquipment> newSupportEquipmentList = meterFixedAssetsMapper.queryEquipmentInfo(equipmentIds);
                for (EquipmentStandardSupportEquipment equipment : newSupportEquipmentList) {
                    DictCodeUtils.convertDictCodeToName(equipment);
                }
                result.setNewSupportEquipmentList(newSupportEquipmentList);
            }
            // 通过标准配套设备id字段查询需要修改的配套设备信息
            List<Long> supportEquipmentIds = meterStandardApplyEquipments.stream().map(EquipmentStandardApplyEquipment::getSupportEquipmentId).collect(Collectors.toList());
            List<EquipmentStandardSupportEquipment> oldSupportEquipmentList = standardSupportMapper.selectBatchEquipmentIds(supportEquipmentIds);
            // 通过标准配套设备表中的设备id查询出设备详细信息
            List<Long> oldEquipmentIds = oldSupportEquipmentList.stream()
                    .filter(e -> {
                        return e.getStandardEquipmentId().equals(request.getId());
                    })
                    .map(EquipmentStandardSupportEquipment::getEquipmentId).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(oldEquipmentIds) && oldEquipmentIds.size()!=0){
                List<EquipmentStandardSupportEquipment> equipmentList = meterFixedAssetsMapper.queryEquipmentInfo(oldEquipmentIds);
                for (EquipmentStandardSupportEquipment equipment : equipmentList) {
                    DictCodeUtils.convertDictCodeToName(equipment);
                }
                result.setOldSupportEquipmentList(equipmentList);
            }
        }
        QueryWrapper<EquipmentStandardApplyFile> applyFileWrapper = new QueryWrapper<>();
        applyFileWrapper.eq("standard_apply_id",result.getId());
        // 查询对应附件列表
        List<EquipmentStandardApplyFile> applyFileList = standardApplyFileMapper.selectList(applyFileWrapper);
        result.setFileList(applyFileList);
        return result;
    }

    @Override
    @Transactional
    public ReturnDTO addStandardEquipmentApply(EquipmentStandardApply meterStandardApply) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        meterStandardApply.setCreateUser(String.valueOf(user.getId()));
        Long maxNo = meterStandardApplyMapper.selectMaxNo();
        String applyNo = NumberGeneratorUtil.getContactNo(getApplyNoPrefix(meterStandardApply.getApplyType()), maxNo);
        meterStandardApply.setApplyNo(applyNo);
        meterStandardApply.setApprovalStatus(ApprovalStatusEnum.DRAFT);
        // 新增标准装置申请基本信息
        if(meterStandardApplyMapper.insert(meterStandardApply)>0){
            if(saveBatch(meterStandardApply)){
                return ReturnUtil.success(meterStandardApply.getId());
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO updateStandardEquipmentApply(EquipmentStandardApply meterStandardApply) {
        if(meterStandardApplyMapper.updateById(meterStandardApply)>0){
            remove(meterStandardApply.getId());
            if(saveBatch(meterStandardApply)){
                return ReturnUtil.success();
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public void exportList(StandardEquipmentApplyRequest request, HttpServletResponse response) throws Exception{
        List<EquipmentStandardApply> resultList;
        if(!CollectionUtils.isEmpty(request.getIds())){
            StandardEquipmentApplyRequest applyRequest = new StandardEquipmentApplyRequest();
            applyRequest.setIds(request.getIds());
            resultList = meterStandardApplyMapper.standardEquipmentList(applyRequest);
        }else{
            request.setBusinessKeys(EquipmentStateManageServiceImpl.getBusinessKeys(request.getApprovalStatus(), request.getFormId(),baseApprovalService));
            if(!request.getApprovalStatus().equals(ApprovalStatusEnum.DRAFT)){
                request.setApprovalStatus(null);
            }
            resultList = meterStandardApplyMapper.standardEquipmentList(request);
        }
        for (EquipmentStandardApply item: resultList) {
            DictCodeUtils.convertDictCodeToName(item);
        }
        iBaseExportService.exportExcel(response, EquipmentStandardApply.class,resultList, ExportEnum.STANDARD_EQUIPMENT_APPLY.getSheetName());
    }

    @Override
    @Transactional
    public ReturnDTO submitStandardEquipmentApply(BaseApprovalSubmitRequest request) {
        //已取消后的提交需先删除原有实例
        if (StringUtils.isNotEmpty(request.getProcessId())){
            runtimeService.updateBusinessStatus(request.getProcessId(), ApprovalStatusEnum.DELETED);
            runtimeService.deleteProcessInstance(request.getProcessId(), "删除");
        }

        ReturnDTO returnDTO = baseApprovalService.processSubmit(request.getFormId(), request.getId());
        if(ResponseData.DEFAULT_SUCCESS_CODE != returnDTO.getCode()){
            return returnDTO;
        }
        ProcessInstance processInstance = (ProcessInstance)returnDTO.getData();
        EquipmentStandardApply meterStandardApply = meterStandardApplyMapper.selectById(request.getId());
        meterStandardApply.setApprovalStatus(ApprovalStatusEnum.UN_DRAFT); //非草稿状态
        meterStandardApply.setProcessId(processInstance.getId());
        int row = this.baseMapper.updateById(meterStandardApply);
        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 approvalDelete(ApprovalDeleteRequest request) {
        int flag = 0;
        // 审批操作-删除
        if(StringUtils.isNotEmpty(request.getTaskId())){
            // 删除表单对应流程实例
            ReturnDTO returnDTO = approvalOperateService.delete(request);
            if(ResponseData.DEFAULT_SUCCESS_CODE == returnDTO.getCode()){
                //本地删除
                flag = meterStandardApplyMapper.deleteById(request.getId());
            }
        }else{
            // 草稿箱等非审批操作删除
            flag = meterStandardApplyMapper.deleteById(request.getId());
        }
        if(flag>0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO failUpdate(EquipmentStandardApply meterStandardApply) {
        if(meterStandardApplyMapper.updateById(meterStandardApply)>0){
            remove(meterStandardApply.getId());
            if(saveBatch(meterStandardApply)){
                baseApprovalService.failUpdate(meterStandardApply.getProcessId());
                return ReturnUtil.success();
            }
            throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    private void remove(Long id){
        QueryWrapper<EquipmentStandardApplyFile> fileWrapper = new QueryWrapper<>();
        fileWrapper.eq("standard_apply_id",id);
        meterStandardApplyFileService.remove(fileWrapper);
        QueryWrapper<EquipmentStandardApplyEquipment> equipmentWrapper = new QueryWrapper<>();
        equipmentWrapper.eq("standard_apply_id",id);
        standardApplyEquipmentService.remove(equipmentWrapper);
    }
    private boolean saveBatch(EquipmentStandardApply meterStandardApply){
        boolean fileSaveFlag = true;
        boolean equipmentFlag = true;
        Long id = meterStandardApply.getId();
        if(!CollectionUtils.isEmpty(meterStandardApply.getApplyEquipmentList())){
            for (EquipmentStandardApplyEquipment applyEquipment : meterStandardApply.getApplyEquipmentList()) {
                applyEquipment.setStandardApplyId(id);
            }
            // 新增标准装置配套设备表
            equipmentFlag = standardApplyEquipmentService.saveBatch(meterStandardApply.getApplyEquipmentList());
        }
        if(!CollectionUtils.isEmpty(meterStandardApply.getFileList())){
            for (EquipmentStandardApplyFile applyFile : meterStandardApply.getFileList()) {
                applyFile.setStandardApplyId(id);
            }
            // 新增对应附件表
            fileSaveFlag = meterStandardApplyFileService.saveBatch(meterStandardApply.getFileList());
        }
        if(fileSaveFlag && equipmentFlag){
            return true;
        }
        return false;
    }

    private String getApplyNoPrefix(String applyType){
        switch (applyType){
            case StandardApplyTypeEnum.REPLACE_APPLY:
                return "ghsq";
            case StandardApplyTypeEnum.SUSPEND_APPLY:
                return "ztsq";
            case StandardApplyTypeEnum.REVOKE_APPLY:
                return "cxsq";
            case StandardApplyTypeEnum.RECOVERY_APPLY:
                return "hfsq";
            case StandardApplyTypeEnum.REVIEW_APPLY:
                return "fcsq";
            default:
                return "";
        }
    }

}
