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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.stream.CollectorUtil;
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.page.PageFactory;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.BaseApprovalSubmitRequest;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.business.print.CertificateListRequest;
import com.casic.missiles.dto.business.print.CertificateListResponse;
import com.casic.missiles.dto.business.print.CertificatePrintDetail;
import com.casic.missiles.dto.business.print.CertificateRefusePrintRequest;
import com.casic.missiles.dto.flowable.ApprovalAgreeRequest;
import com.casic.missiles.dto.flowable.ApprovalRefuseRequest;
import com.casic.missiles.dto.flowable.ToBeApprovedDTO;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.enums.ExportEnum;
import com.casic.missiles.enums.business.CertificatePrintStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.business.BusinessCertificatePrintMapper;
import com.casic.missiles.model.business.BusinessCertificatePrint;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.business.IBusinessCertificatePrintService;
import com.casic.missiles.service.flowable.ApprovalOperateService;
import com.casic.missiles.utils.DictCodeUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ProcessInstance;
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 cz
 */
@Service
@AllArgsConstructor
public class BusinessCertificatePrintServiceImpl extends ServiceImpl<BusinessCertificatePrintMapper, BusinessCertificatePrint> implements IBusinessCertificatePrintService, CertificatePrintStatusEnum {

    private final IBaseApprovalService baseApprovalService;
    private final IBaseExportService iBaseExportService;
    private final ApprovalOperateService approvalOperateService;
    @Resource
    private RuntimeService runtimeService;

    @Override
    public Page<CertificateListResponse> certificatePrintListPage(CertificateListRequest request, Page<CertificateListResponse> page) throws Exception {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        request.setCreateUserId(user.getId());
        return handleApprovalStatus(page, request);
    }

    @Override
    public CertificatePrintDetail certificatePrintDetail(Long id) {
        CertificatePrintDetail certificatePrintDetail = this.baseMapper.selectPrintDetailById(id);
        return certificatePrintDetail;
    }

    @Override
    public void certificatePrintExport(CertificateListRequest request, HttpServletResponse response, Page<CertificateListResponse> page) throws Exception {
        try {
            AuthUser user = ShiroKit.getUser();
            Assert.isFalse(Objects.isNull(user), () -> {
                throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
            });
            if (CollectionUtils.isEmpty(request.getIds())) {
                request.setIds(null);
            }
            page.setCurrent(1);
            page.setSearchCount(false);
            page.setSize(Integer.MAX_VALUE);
            request.setCreateUserId(user.getId());
            Page<CertificateListResponse> certificateListResponsePage = handleApprovalStatus(page, request);
            iBaseExportService.exportExcel(response, CertificateListResponse.class, certificateListResponsePage.getRecords(), ExportEnum.CERTIFICATE_PRINT_EXPORT.getSheetName());
        } catch (Exception e) {
            log.error("证书打印导出出现异常，异常信息为{}", e);
        }
    }

    @Override
    public ReturnDTO certificatePrintStatus(Long id, String printStatus) {
        BusinessCertificatePrint businessCertificatePrint = BusinessCertificatePrint.builder()
                .id(id)
                .printStatus(printStatus)
                .build();
        int updatePrintStatus = this.baseMapper.updateById(businessCertificatePrint);
        if (updatePrintStatus > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO agreeAgainPrint(ApprovalAgreeRequest request) {
        return approvalOperateService.agree(request);
    }

    /**
     * 更新工作流审批状态为拒绝，当返回值成功时，进行打印状态置为不可打印，审批状态为不通过
     *
     * @return
     */
    @Override
    @Transactional
    public ReturnDTO refuseAgainPrint(CertificateRefusePrintRequest request) {
        ApprovalRefuseRequest approvalRefuseRequest = new ApprovalRefuseRequest();
        approvalRefuseRequest.setTaskId(request.getTaskId());
        approvalRefuseRequest.setComments(request.getComments());
        ReturnDTO returnDTO = approvalOperateService.refuse(approvalRefuseRequest);
        if (!ResponseData.DEFAULT_SUCCESS_CODE.equals(returnDTO.getCode())) {
            return returnDTO;
        }
        BusinessCertificatePrint certificatePrint = BusinessCertificatePrint.builder()
                .id(request.getId())
                .printStatus(NON_PRINTABLE)
                .approvalStatus(ApprovalStatusEnum.FAILED)
                .build();
        int row = this.baseMapper.updateById(certificatePrint);
        if (row <= 0) {
            throw new BusinessException(BusinessExceptionEnum.AGAIN_PRINT_SUBMIT_FAILED.getCode(), BusinessExceptionEnum.AGAIN_PRINT_SUBMIT_FAILED.getMessage());
        }
        return ReturnUtil.success();
    }

    /**
     * 提交审批流程，修改证书审批状态为待审批，打印状态为审批中
     */
    @Transactional
    @Override
    public ReturnDTO submitAgainPrint(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.equals(returnDTO.getCode())) {
            return returnDTO;
        }
        ProcessInstance processInstance = (ProcessInstance) returnDTO.getData();
        BusinessCertificatePrint certificatePrint = BusinessCertificatePrint.builder()
                .id(request.getId())
                .processId(processInstance.getId())
                .approvalStatus(ApprovalStatusEnum.IN_APPROVED)
                .printStatus(IN_APPROVAL)
                .build();
        int row = this.baseMapper.updateById(certificatePrint);
        if (row <= 0) {
            throw new BusinessException(BusinessExceptionEnum.AGAIN_PRINT_SUBMIT_FAILED.getCode(), BusinessExceptionEnum.AGAIN_PRINT_SUBMIT_FAILED.getMessage());
        }
        return ReturnUtil.success();
    }

    /**
     * 可打印：只需要查询可打印状态即可，待审批状态，查询工作流，同时传输任务id
     */
    private Page<CertificateListResponse> handleApprovalStatus(Page<CertificateListResponse> page, CertificateListRequest request) throws Exception {
        Page<CertificateListResponse> approvalList = PageFactory.defaultPage();
        if (ApprovalStatusEnum.TO_BE_APPROVED.equals(request.getApprovalStatus()) && CollectionUtils.isEmpty(request.getIds())) {
            approvalList = handlerBeApproved(approvalList, page, request);
        } else {
            if ("0".equals(request.getApprovalStatus())) {
                request.setApprovalStatus("");
            }
            List<String> businessKeys = null;
            if (StringUtils.isNotEmpty(request.getApprovalStatus())) {
                switch (request.getApprovalStatus()) {
                    case ApprovalStatusEnum.IN_APPROVED:
                        businessKeys = baseApprovalService.getInApprovedList(request.getFormId());
                        break;
                    case ApprovalStatusEnum.PASSED:
                        businessKeys = baseApprovalService.getPassedList(request.getFormId());
                        break;
                }
            }
            if (CollectionUtil.isEmpty(businessKeys)) {
                businessKeys = null;
            }
            approvalList = this.baseMapper.selectBatchForApprovalList(page, request, businessKeys);
        }
        List<Map<String, String>> staffList = this.baseMapper.getMeterStaffList();
        Map<Long, String> staffMap = staffList.stream().collect(
                Collectors.toMap(e -> Long.valueOf(String.valueOf(e.get("id"))), e -> String.valueOf(e.get("name")))
        );
        for (CertificateListResponse certificateListResponse : approvalList.getRecords()) {
            DictCodeUtils.convertDictCodeToName(certificateListResponse);
            certificateListResponse.setMeasurePersonName(staffMap.get(Long.valueOf(certificateListResponse.getMeasurePersonId())));
        }
        return approvalList;
    }

    /**
     * 查询待审批状态的打印证书，查询业务主键信息，据此查询相应的证书，并填充相应的工作流状态
     */
    private Page<CertificateListResponse> handlerBeApproved(Page<CertificateListResponse> approvalList, Page<CertificateListResponse> page, CertificateListRequest request) {
        List<String> businessKeys = new ArrayList<>();
        List<ToBeApprovedDTO> toBeApprovedList = baseApprovalService.getToBeApprovedList(request.getFormId());
        if (!CollectionUtils.isEmpty(toBeApprovedList)) {
            businessKeys = toBeApprovedList.stream().map(ToBeApprovedDTO::getBusinessKey).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(businessKeys)) {
            request.setApprovalStatus("");
            approvalList = this.baseMapper.selectBatchForApprovalList(page, request, businessKeys);
            //DTO根据业务主键补全taskId
            approvalList.getRecords().forEach(approval -> {
                toBeApprovedList.forEach(toBeApprovedDTO -> {
                    if (String.valueOf(approval.getId()).equals(toBeApprovedDTO.getBusinessKey())) {
                        approval.setApprovalStatus(ApprovalStatusEnum.TO_BE_APPROVED);
                        approval.setTaskId(toBeApprovedDTO.getTaskId());
                        approval.setDecisionItem(toBeApprovedDTO.getDecisionItem());
                    }
                });
            });
        }
        return approvalList;
    }

}
