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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
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.application.service.AbstractDictService;
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.certificate.CertificateMonitorResponse;
import com.casic.missiles.dto.business.certificate.CertificateReportApprovalRequest;
import com.casic.missiles.dto.business.certificate.CertificateReportResponse;
import com.casic.missiles.dto.customer.CertificationResponse;
import com.casic.missiles.dto.customer.sample.CustomerSampleIdRequest;
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.business.CertificatePrintStatusEnum;
import com.casic.missiles.enums.business.MonitorCodeEnum;
import com.casic.missiles.enums.meter.MeterDictEnum;
import com.casic.missiles.enums.system.ApplyFromIdEnum;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.business.BusinessCertificateReportMapper;
import com.casic.missiles.mapper.meter.MeterStaffMapper;
import com.casic.missiles.model.business.BusinessCertificateReport;
import com.casic.missiles.model.business.BusinessOriginalRecord;
import com.casic.missiles.model.customer.CustomerSampleInfo;
import com.casic.missiles.model.meter.MeterStaff;
import com.casic.missiles.model.response.ResponseData;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.Impl.customer.CustomerSampleServiceImpl;
import com.casic.missiles.service.business.IBusinessCertificateReportService;
import com.casic.missiles.service.business.IBusinessOriginalRecordService;
import com.casic.missiles.service.flowable.ApprovalOperateService;
import com.casic.missiles.utils.DictCodeUtils;
import com.casic.missiles.utils.NumberGeneratorUtil;
import com.casic.missiles.utils.PageUtil;
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.factory.annotation.Autowired;
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;

/**
 * <p>
 * 业务管理-证书报告 服务实现类
 * </p>
 *
 * @author zt
 * @since 2023-02-02
 */
@Service
public class BusinessCertificateReportServiceImpl extends ServiceImpl<BusinessCertificateReportMapper, BusinessCertificateReport> implements IBusinessCertificateReportService {


    @Autowired
    private IBusinessOriginalRecordService originalRecordService;
    @Resource
    private AbstractDictService dictService;
    @Autowired
    private IBaseApprovalService baseApprovalService;
    @Autowired
    private ApprovalOperateService approvalOperateService;
    @Resource
    private TaskService taskService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IBaseExportService iBaseExportService;
    @Resource
    private CustomerSampleServiceImpl sampleService;
    @Autowired
    private MeterStaffMapper staffMapper;

    /**
     * 保存证书报告信息
     *
     * @param certificateReport
     * @return
     */
    @Override
    public ReturnDTO saveCertificateReport(BusinessCertificateReport certificateReport) {

        initCertificateReport(certificateReport);
        if (this.baseMapper.insert(certificateReport) > 0)
            return ReturnUtil.success(certificateReport.getId());
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    /***
     * 审批操作-删除,包括删流程和数据库记录
     * @param request
     * @return
     */
    @Override
    public ReturnDTO approvalDelete(ApprovalDeleteRequest request) {
        ReturnDTO returnDTO = approvalOperateService.delete(request);
        if (ResponseData.DEFAULT_SUCCESS_CODE == returnDTO.getCode()) {
            //删除数据库记录
            if (this.baseMapper.deleteById(request.getId()) > 0) {
                return ReturnUtil.success();
            }
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO draftUpdate(BusinessCertificateReport certificateReport) {
        if (this.baseMapper.updateById(certificateReport) > 0) {
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @Override
    public ReturnDTO deleteBatchTraceSupplier(List<Long> ids) {
        return baseMapper.deleteBatchIds(ids) > 0 ? ReturnUtil.success() :
                ReturnUtil.failed("删除失败");
    }

    /**
     * 证书报告详情
     *
     * @param id
     * @return
     */
    @Override
    public BusinessCertificateReport certificateReportDetail(Long id) {
//        BusinessCertificateReport certificateReport = this.baseMapper.selectById(id);
        BusinessCertificateReport certificateReport = this.baseMapper.detailById(id);
        getApprovalSignName(certificateReport);
        if (certificateReport.getOriginalRecordId() != null) {
            try {
                certificateReport.setBusinessOriginalRecord(originalRecordService.originalDetail(certificateReport.getOriginalRecordId()));
                if (Objects.isNull(certificateReport.getBusinessOriginalRecord())) {
                    certificateReport.setBusinessOriginalRecord(new BusinessOriginalRecord());
                }
                certificateReport.setCertificateReportTypeName(dictService.getDictNameByCode(MeterDictEnum.CERTIFICATION_CLASS, certificateReport.getCertificateReportType()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return certificateReport;
    }

    /**
     * 提交证书报告
     *
     * @param request
     * @return
     */
    @Override
    @Transactional
    public ReturnDTO submitCertificateReport(BaseApprovalSubmitRequest request) {
        //已取消后的提交需先删除原有实例
        if (StringUtils.isNotEmpty(request.getProcessId())) {
            runtimeService.updateBusinessStatus(request.getProcessId(), ApprovalStatusEnum.DELETED);
            runtimeService.deleteProcessInstance(request.getProcessId(), "删除");
        }
        //1.根据表单id获取流程定义id
        String formId = request.getFormId();
        //2.根据流程定义id启动流程实例
        ReturnDTO returnDTO = baseApprovalService.processSubmit(formId, request.getId());
        if (ResponseData.DEFAULT_SUCCESS_CODE != returnDTO.getCode()) {
            return returnDTO;
        }
        ProcessInstance processInstance = (ProcessInstance) returnDTO.getData();
        BusinessCertificateReport certificateReport = new BusinessCertificateReport();
        certificateReport.setId(request.getId());
        certificateReport.setApprovalStatus(ApprovalStatusEnum.UN_DRAFT); //非草稿状态
        certificateReport.setProcessId(processInstance.getId());
        certificateReport.setSubmitDate(DateUtil.formatDateTime(new Date()));
        certificateReport.setUpdateTime(DateUtil.formatDateTime(new Date()));
        int row = this.baseMapper.updateById(certificateReport);
        if (row <= 0) {
            throw new BusinessException(BusinessExceptionEnum.CERTIFICATE_REPORT_SUBMIT_FAILED.getCode(), BusinessExceptionEnum.CERTIFICATE_REPORT_SUBMIT_FAILED.getMessage());
        }
        return ReturnUtil.success();
    }


    /**
     * 审批状态列表查询
     *
     * @param page
     * @param request
     * @return
     */
    @Override
    public List<CertificateReportResponse> approvalListPage(Page<CertificateReportResponse> page, CertificateReportApprovalRequest request) {
        //登录用户
        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);
    }

    /**
     * 驳回后更新
     *
     * @param certificateReport
     * @return
     */
    @Override
    public ReturnDTO failUpdate(BusinessCertificateReport certificateReport) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        if (this.baseMapper.updateById(certificateReport) > 0) {
            baseApprovalService.failUpdate(certificateReport.getProcessId());
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public void originExport(CertificateReportApprovalRequest request, HttpServletResponse response) {
        try {
            //登录用户
            AuthUser user = ShiroKit.getUser();
            Assert.isFalse(Objects.isNull(user), () -> {
                throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
            });
            request.setCreateUserId(user.getId());
            List<CertificateReportResponse> reportResponseList = handleApprovalStatus(null, request);
            iBaseExportService.exportExcel(response, CertificateReportResponse.class, reportResponseList, ExportEnum.CERTIFICATE_REPORT.getSheetName());
        } catch (Exception e) {
            log.error("证书报告导出出现异常，异常信息为{}", e);
        }
    }

    /**
     * 审批通过后  更新样品有效期
     *
     * @param id
     * @return
     */
    @Override
    public boolean updateCertificateReportState(Long id) {

        BusinessCertificateReport certificateReport = new BusinessCertificateReport();
        certificateReport.setId(id);
        //审批状态为通过
        certificateReport.setApprovalStatus(ApprovalStatusEnum.PASSED);
        certificateReport.setUpdateTime(DateUtil.formatDateTime(new Date()));
        int row = this.baseMapper.updateById(certificateReport);
        //更新样品有效期
        BusinessCertificateReport certificateReport1 = this.baseMapper.selectById(id);
        if (certificateReport1.getSampleId() != null) {
            CustomerSampleInfo sampleInfo = sampleService.getById(certificateReport1.getSampleId());
            if (sampleInfo != null) {
                sampleInfo.setValidDeadline(certificateReport1.getExpirationDate());
                boolean rs = sampleService.updateById(sampleInfo);
                if (row > 0 && rs) return true;
            }
        }
        return row > 0 ? true : false;
    }


    /**
     * 客户、样品详情列表
     */
    @Override
    public Page<CertificationResponse> certificateRecordsById(CustomerSampleIdRequest customerSampleIdRequest) throws Exception {
        Page<CertificationResponse> page = PageFactory.defaultPage();
        Page<CertificationResponse> certificateResponsePage = this.baseMapper.certificateRecordsById(page, customerSampleIdRequest);
        for (CertificationResponse customerSampleListResponse : certificateResponsePage.getRecords()) {
            if (!StringUtils.isEmpty(customerSampleListResponse.getCertificationClass())) {
                DictCodeUtils.convertDictMultiCodeToName(customerSampleListResponse);
            }
        }
        return certificateResponsePage;
    }

    @Override
    public Page<CertificateMonitorResponse> certificateMonitorsById(CustomerSampleIdRequest customerSampleIdRequest) throws Exception {
        Page<CertificateMonitorResponse> page = PageFactory.defaultPage();
        Page<CertificateMonitorResponse> certificateMonitorResponsePage = this.baseMapper.certificateMonitorsById(page, customerSampleIdRequest);
        for (CertificateMonitorResponse certificateMonitorResponse : certificateMonitorResponsePage.getRecords()) {
            if (!StringUtils.isEmpty(certificateMonitorResponse.getCertificationType())) {
                DictCodeUtils.convertDictMultiCodeToName(certificateMonitorResponse);
            }
            //设置证书状态
            certificateMonitorResponse.setCertificateStatus(ApprovalStatusEnum.PASSED.equals(certificateMonitorResponse.getCertificateStatus()) ?
                    CertificatePrintStatusEnum.FINISHED : CertificatePrintStatusEnum.UNFINISHED);
            //设置完成时间
            certificateMonitorResponse.setFinishedTime(ApprovalStatusEnum.PASSED.equals(certificateMonitorResponse.getCertificateStatus()) ?
                    certificateMonitorResponse.getFinishedTime() : "");

            //设置退回次数
            List<String> rejectBusinessKey = baseApprovalService.getFailedRejectList(ApplyFromIdEnum.CERTIFICATE_REPORT_APPROVAL.getCode());

            rejectBusinessKey.forEach(obj -> {
                if (obj.equals(certificateMonitorResponse.getCertificationId().toString())) {
                    certificateMonitorResponse.setReturns(certificateMonitorResponse.getReturns() + 1);
                }
            });
        }
        return certificateMonitorResponsePage;
    }

    private List<CertificateReportResponse> handleApprovalStatus(Page<CertificateReportResponse> page, CertificateReportApprovalRequest request) {
        List<CertificateReportResponse> approvalList = new ArrayList<>();
        List<String> businessKeys = new ArrayList<>();
        switch (request.getApprovalStatus()) {
            //草稿
            case ApprovalStatusEnum.DRAFT:
                approvalList = handleApprovalListResponse(this.baseMapper.selectDraftListForApproval(page, request), ApprovalStatusEnum.DRAFT);
                break;
            //待审批，该状态维护在flowable中
            case ApprovalStatusEnum.TO_BE_APPROVED:
                List<ToBeApprovedDTO> toBeApprovedList = baseApprovalService.getToBeApprovedList(request.getFormId());
                if (!CollectionUtils.isEmpty(toBeApprovedList)) {
                    businessKeys = toBeApprovedList.stream().map(ToBeApprovedDTO::getBusinessKey).distinct().collect(Collectors.toList());
                }
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), ApprovalStatusEnum.TO_BE_APPROVED);
                    //DTO根据业务主键补全taskId
                    approvalList.forEach(approval -> {
                        toBeApprovedList.forEach(toBeApprovedDTO -> {
                            if (String.valueOf(approval.getId()).equals(toBeApprovedDTO.getBusinessKey())) {
                                approval.setTaskId(toBeApprovedDTO.getTaskId());
                                //补全可选决策项
                                approval.setDecisionItem(toBeApprovedDTO.getDecisionItem());
                            }
                        });
                    });
                }
                break;
            //审批中，该状态维护在flowable中
            case ApprovalStatusEnum.IN_APPROVED:
                businessKeys = baseApprovalService.getInApprovedList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), ApprovalStatusEnum.IN_APPROVED);
                }
                break;
            //已通过，该状态维护在flowable
            case ApprovalStatusEnum.PASSED:
                businessKeys = baseApprovalService.getPassedList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), ApprovalStatusEnum.PASSED);
                }
                break;
            //未通过（包括拒绝、驳回，拒绝为直接删除实例，驳回为驳回到起点），该状态维护在flowable
            case ApprovalStatusEnum.FAILED:
                businessKeys = baseApprovalService.getFailedList(request.getFormId()); //未通过-拒绝
                List<String> rejectBusinessKey = baseApprovalService.getFailedRejectList(request.getFormId()); //未通过-驳回
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), ApprovalStatusEnum.FAILED);
                }
                List<CertificateReportResponse> rejectApprovalList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(rejectBusinessKey)) {
                    rejectApprovalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, rejectBusinessKey), ApprovalStatusEnum.FAILED_REJECT);
                }
                //合并未通过-拒绝和未通过-驳回
                approvalList.addAll(rejectApprovalList);
                //分页处理
                if(!CollectionUtils.isEmpty(approvalList)) {
                    Page pages = PageUtil.getPages((int) page.getCurrent(), (int) page.getSize(), approvalList);
                    page.setTotal(approvalList.size());
                    approvalList = pages.getRecords();
                }
                break;
            //已取消，该状态维护在flowable
            case ApprovalStatusEnum.CANCELED:
                businessKeys = baseApprovalService.getCanceledList(request.getFormId());
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), ApprovalStatusEnum.CANCELED);
                }
                break;
            //全部
            //区分管理员和普通用户
            //普通用户获取自己发起的(审批中、已通过、未通过、已取消)，管理员获取全部(审批中、已通过、未通过、已取消)
            case ApprovalStatusEnum.ALL:
                List<AllApproveDTO> AllApproveList = baseApprovalService.getAllList(request.getFormId());
                if (!CollectionUtils.isEmpty(AllApproveList)) {
                    businessKeys = AllApproveList.stream().map(AllApproveDTO::getBusinessKey).collect(Collectors.toList());
                }
                if (!CollectionUtils.isEmpty(businessKeys)) {
                    approvalList = handleAllApprovalListResponse(this.baseMapper.selectBatchForApproval(page, request, businessKeys), AllApproveList);
                }
                break;
        }
        return approvalList;
    }

    private List<CertificateReportResponse> handleAllApprovalListResponse(List<CertificateReportResponse> approvalList, List<AllApproveDTO> allApproveList) {
        Map<String, String> taskMap = new HashMap<>();
        allApproveList.forEach(allApprove -> {
            taskMap.put(allApprove.getBusinessKey(), allApprove.getStatus());
        });
        //状态补全
        approvalList.forEach(approval -> {
            approval.setApprovalStatusName(dictService.getDictNameByCode(MeterDictEnum.APPROVAL_STATUS, taskMap.get(String.valueOf(approval.getId()))));
            approval.setApprovalStatus(taskMap.get(String.valueOf(approval.getId())));
            approval.setMeasureCategoryName(dictService.getDictNameByCode(MeterDictEnum.MEASURE_CATEGORY, approval.getMeasureCategory()));

        });
        //排序
        return approvalList.stream().sorted(Comparator.comparing(CertificateReportResponse::getCreateTime).reversed()).collect(Collectors.toList());
    }

    /**
     * 设置多项认可章的属性
     */
    private void getApprovalSignName(BusinessCertificateReport certificateReport) {
        if (StringUtils.isNotEmpty(certificateReport.getApprovalSignIds())) {
            List<Map<String, Object>> approvalSignNameList = this.baseMapper.approvalSignName();
            Map<Long, String> approvalSignNameMap = approvalSignNameList.stream().collect(Collectors.toMap(
                    e -> Long.valueOf(String.valueOf(e.get("id"))), e -> String.valueOf(e.get("signName"))
            ));
            String approvalSignNames = "";
            String[] approvalSignIds = certificateReport.getApprovalSignIds().split(",");
            for (String approvalSignId : approvalSignIds) {
                approvalSignNames += approvalSignNameMap.get(Long.valueOf(approvalSignId))+ ",";
            }
            approvalSignNames = approvalSignNames.substring(0, approvalSignNames.length() - 1);
            certificateReport.setApprovalSignName(approvalSignNames);
        }
    }

    private List<CertificateReportResponse> handleApprovalListResponse(List<CertificateReportResponse> approvalList, String status) {
        approvalList.stream().forEach(result -> {
            //审批状态两种获取方式：1、在此处设置，2、在flowable中设置业务状态，暂采取1
            result.setApprovalStatusName(dictService.getDictNameByCode(MeterDictEnum.APPROVAL_STATUS, status));
            result.setMeasureCategoryName(dictService.getDictNameByCode(MeterDictEnum.MEASURE_CATEGORY, result.getMeasureCategory()));
        });
        return approvalList;
    }

    private void initCertificateReport(BusinessCertificateReport certificateReport) {
        String prefix = MonitorCodeEnum.getByCode(certificateReport.getCalibrationMajor()).getValue()
                + DateUtil.format(new Date(), "YYYYMM");
        Long maxNo = this.baseMapper.selectMaxCode(prefix);
        //生成证书编号
        String certificateReportNo = NumberGeneratorUtil.getCode(
                MonitorCodeEnum.getByCode(certificateReport.getCalibrationMajor()).getValue(), maxNo);
        AuthUser authUser = ShiroKit.getUser();
        certificateReport.setCreateUser(authUser.getId());
        MeterStaff meterStaff = getMeterStaffInfo(authUser);
        if (Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        certificateReport.setMeasurePersonId(meterStaff.getId());
        certificateReport.setMeasureDeptId(authUser.getDeptId());
        certificateReport.setCertificateReportCode(certificateReportNo);
        certificateReport.setCreateTime(DateUtil.formatDateTime(new Date()));
    }

    private MeterStaff getMeterStaffInfo(AuthUser user) {
        String account = user.getAccount();
        QueryWrapper<MeterStaff> wrapper = new QueryWrapper<>();
        wrapper.eq("account", account);
        return staffMapper.selectOne(wrapper);
    }
}
