package digital.laboratory.platform.entrustment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import digital.laboratory.platform.common.core.constant.OSSDirectoryConstants;
import digital.laboratory.platform.common.core.exception.ValidateCodeException;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.common.oss.service.OssFile;
import digital.laboratory.platform.common.security.util.SecurityUtils;
import digital.laboratory.platform.entrustment.convert.DrugLiteConvert;
import digital.laboratory.platform.entrustment.dto.ApprovedUpdateEntrustDTO;
import digital.laboratory.platform.entrustment.dto.EntrustAlterApplyApproveDTO;
import digital.laboratory.platform.entrustment.dto.EntrustAlterApplyDTO;
import digital.laboratory.platform.entrustment.dto.MaterialDTO;
import digital.laboratory.platform.entrustment.entity.CaseEvent;
import digital.laboratory.platform.entrustment.entity.EntrustAlterApply;
import digital.laboratory.platform.entrustment.entity.Entrustment;
import digital.laboratory.platform.entrustment.entity.EntrustmentIdentificationMaterial;
import digital.laboratory.platform.entrustment.enums.AnalysisOptionEnums;
import digital.laboratory.platform.entrustment.enums.EntrustAlterApplyStatus;
import digital.laboratory.platform.entrustment.mapper.EntrustAlterApplyMapper;
import digital.laboratory.platform.entrustment.query.EntrustAlterApplyQuery;
import digital.laboratory.platform.entrustment.service.*;
import digital.laboratory.platform.entrustment.vo.EntrustAlterApplyVO;
import digital.laboratory.platform.sys.entity.DrugLite;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author ChenJiangBao
* @description 针对表【b_entrust_alter_apply(申请修改委托消息表)】的数据库操作Service实现
* @createDate 2024-10-31 17:35:01
*/
@Service
public class EntrustAlterApplyServiceImpl extends ServiceImpl<EntrustAlterApplyMapper, EntrustAlterApply>
    implements EntrustAlterApplyService{

    @Resource
    private OssFile ossFile;

    @Resource
    private CommonFeignService commonFeignService;

    @Resource
    private CaseEventService caseEventService;

    @Resource
    private EntrustmentService entrustmentService;

    @Resource
    private EntrustmentIdentificationMaterialService entrustmentIdentificationMaterialService;


    @Override
    public IPage<EntrustAlterApplyVO> voPage(EntrustAlterApplyQuery query) {
        DLPUser user = SecurityUtils.getUser();
        if (!user.isStaff()) {
            query.setClientOrgId(user.getOrgId());
            query.setIsStaff(false);
        }
        IPage<EntrustAlterApplyVO> entrustAlterApplyVOPage = baseMapper.getEntrustAlterApplyVOPage(new Page<>(query.getCurrent(), query.getSize()), query);
        entrustAlterApplyVOPage.getRecords().forEach(this::fillVOInfo);
        return entrustAlterApplyVOPage;
    }

    /**
     * 保存消息
     * @param dto 保存的参数
     * @return
     */
    @Override
    public EntrustAlterApplyVO save(EntrustAlterApplyDTO dto) {
        // 对当前委托进行校验，如果有关联该委托的申请信息，判断状态如果不是已完成则提示先完成当前申请
        if (isApplying(dto.getEntrustId())) {
            throw new ValidateCodeException("该委托存在未完成的申请信息，请先完成其他申请后再进行申请修改！");
        }

        EntrustAlterApply entrustAlterApply = new EntrustAlterApply();
        if (StrUtil.isBlank(dto.getId())) {
            entrustAlterApply.setEntrustId(dto.getEntrustId());
            DLPUser user = SecurityUtils.getUser();
            entrustAlterApply.setApplicant(user.getId());
            entrustAlterApply.setApplyOrgId(user.getOrgId());
            entrustAlterApply.setApplyReason(dto.getApplyReason());
            if (dto.getOpCode() == 0) {
                entrustAlterApply.setStatus(EntrustAlterApplyStatus.WAIT_SUBMIT_APPLY.getStatus());
            } else if (dto.getOpCode() == 1) {
                entrustAlterApply.setApplyDate(LocalDate.now());
                entrustAlterApply.setStatus(EntrustAlterApplyStatus.SUBMITTED_WAIT_APPROVE.getStatus());
            }
            super.save(entrustAlterApply);
        } else {
            entrustAlterApply.setId(dto.getId());
            super.update(Wrappers.<EntrustAlterApply>lambdaUpdate()
                    .eq(EntrustAlterApply::getId, dto.getId())
                    .set(EntrustAlterApply::getStatus, EntrustAlterApplyStatus.SUBMITTED_WAIT_APPROVE.getStatus())
                    .set(EntrustAlterApply::getApplyDate, LocalDate.now()));

        }
        EntrustAlterApplyVO entrustAlterApplyVOOne = baseMapper.getEntrustAlterApplyVOOne(Wrappers.<EntrustAlterApply>query().eq("eaa.id", entrustAlterApply.getId()));
        fillVOInfo(entrustAlterApplyVOOne);
        return entrustAlterApplyVOOne;
    }

    /**
     * 审批委托申请修改
     * @param approveDTO
     * @return
     */
    @Override
    public Boolean approve(EntrustAlterApplyApproveDTO approveDTO) {
        // 判断当前申请是否在可以审核的状态
        EntrustAlterApply entrustAlterApply = super.getById(approveDTO.getId());
        if (entrustAlterApply == null) {
            throw new ValidateCodeException("申请记录不存在!");
        }
        if (!entrustAlterApply.getStatus().equals(EntrustAlterApplyStatus.SUBMITTED_WAIT_APPROVE.getStatus())) {
            throw new ValidateCodeException("当前申请状态不允许审核!");
        }

        // 直接根据opCode设置状态
        EntrustAlterApplyStatus status;
        if (approveDTO.getOpCode() == 0) {
            status = EntrustAlterApplyStatus.APPLY_FAIL;
        } else {
            status = EntrustAlterApplyStatus.APPLY_SUCCESS;
        }

        // 合并重复的update操作
        return super.update(
                Wrappers.<EntrustAlterApply>lambdaUpdate()
                        .eq(EntrustAlterApply::getId, approveDTO.getId())
                        .set(EntrustAlterApply::getReviewer, SecurityUtils.getUser().getId())
                        .set(EntrustAlterApply::getStatus, status.getStatus())
                        .set(EntrustAlterApply::getReason, approveDTO.getReason())
        );
    }

    /**
     * 修改消息
     * @param dto
     * @return
     */
    @Override
    public Boolean update(EntrustAlterApplyDTO dto) {
        if(StrUtil.isBlank(dto.getId())){
            throw new ValidateCodeException("修改的记录id不能为空");
        }
        EntrustAlterApply oldInfo = super.getById(dto.getId());
        DLPUser user = SecurityUtils.getUser();
        if (!oldInfo.getApplicant().equals(user.getId())) {
            throw new ValidateCodeException("请勿修改其他人的申请信息！");
        }
        if (dto.getOpCode() == 1 && oldInfo.getStatus().equals(EntrustAlterApplyStatus.SUBMITTED_WAIT_APPROVE.getStatus())) {
            throw new ValidateCodeException("该条记录不在可撤销的状态范围内!");
        }
        return super.update(Wrappers.<EntrustAlterApply>lambdaUpdate().eq(EntrustAlterApply::getId, dto.getId())
                .set(EntrustAlterApply::getEntrustId, dto.getEntrustId())
                .set(StrUtil.isNotBlank(dto.getApplyReason()), EntrustAlterApply::getApplyReason, dto.getApplyReason())
                .set(dto.getOpCode() == 1,
                        EntrustAlterApply::getStatus, EntrustAlterApplyStatus.WAIT_SUBMIT_APPLY.getStatus()));
    }

    /**
     * 删除委托申请修改消息
     * @param ids
     * @return
     */
    @Override
    public Boolean delete(List<String> ids) {
        List<EntrustAlterApplyVO> entrustAlterAppliesVOS = baseMapper.getEntrustAlterApplyVOList(Wrappers.<EntrustAlterApply>query().in("eaa.id",ids));
        DLPUser user = SecurityUtils.getUser();
        entrustAlterAppliesVOS.forEach(e -> {
            if (!e.getApplicant().equals(user.getId())) {
                throw new ValidateCodeException("请勿修改其他人的申请信息！");
            }
            if (e.getStatus().equals(EntrustAlterApplyStatus.WAIT_SUBMIT_APPLY.getStatus())) {
                throw new ValidateCodeException(String.format("案件名称为 %s 的记录不在可删除的状态，无法删除!", e.getCaseName()));
            }
        });
        return super.remove(Wrappers.<EntrustAlterApply>lambdaUpdate().in(EntrustAlterApply::getId,ids));
    }

    /**
     * 修改委托案件简要、鉴定要求, 并删除已生成的鉴定事项确认书和委托书
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateEntrust(ApprovedUpdateEntrustDTO dto) {
        Entrustment entrustment = validUpdateInfoAndGetEntrustInfo(dto);
        // 提取委托id
        StringBuilder updateRecordBuilder = new StringBuilder();
        String entrustmentId = entrustment.getId();
        CaseEvent oldCaseInfo = caseEventService.getById(entrustment.getCaseId());
        caseEventService.update(Wrappers.<CaseEvent>lambdaUpdate().eq(CaseEvent::getId, entrustment.getCaseId()).set(CaseEvent::getCaseBrief, dto.getCaseBrief()));
        // 添加更新记录  | <br> 代表换行
        updateRecordBuilder.append("操作记录：").append("<br>该委托案件的案件简要由 [").append(oldCaseInfo.getCaseBrief()).append("] 更改为 [").append(dto.getCaseBrief()).append("] 。");
        // 2.修改检材 信息
        // 这里之所以要取未更新前的信息是为了留痕
        Map<String, EntrustmentIdentificationMaterial> oldInfoMap = entrustmentIdentificationMaterialService.list(Wrappers.<EntrustmentIdentificationMaterial>lambdaQuery()
                .eq(EntrustmentIdentificationMaterial::getEntrustmentId, entrustmentId)
                .orderByAsc(EntrustmentIdentificationMaterial::getOrderNo))
                .stream().collect(Collectors.toMap(EntrustmentIdentificationMaterial::getId, Function.identity()));
        List<MaterialDTO> materialList = dto.getMaterialList();
        Integer index = 1;
        List<EntrustmentIdentificationMaterial> entrustmentIdentificationMaterialList = new ArrayList<>();
        for (MaterialDTO item : materialList) {
            String materialId = item.getId();
            String name = item.getName();
            List<DrugLite> candidateDrugs = item.getCandidateDrugs();
            String renewDrugsStr = candidateDrugs.stream().map(DrugLite::getName).collect(Collectors.joining("、"));
            Integer analysisOption = item.getAnalysisOption();
            EntrustmentIdentificationMaterial oldMaterial = oldInfoMap.get(materialId);
            String oldDrugsStr = DrugLiteConvert.convertDirtyLiteByJSON(oldMaterial.getCandidateDrugs()).stream().map(DrugLite::getName).collect(Collectors.joining("、"));
            // 判断有没有对这个检材进行修改oldMaterial.getName().equals(name) && oldMaterial.getAnalysisOption().equals(analysisOption) && oldDrugsStr.equals(renewDrugsStr)

            boolean equalsName = oldMaterial.getName().equals(name);
            boolean equalsAnalysisOption = oldMaterial.getAnalysisOption().equals(analysisOption);
            boolean equalsDrugInfo = oldDrugsStr.equals(renewDrugsStr);
            if (equalsName && equalsAnalysisOption && equalsDrugInfo) {
                // 信息并没有修改，不操作
                continue;
            }
            if (index == 1) {
                updateRecordBuilder.append("<br>检材信息的更新记录：");
            }
            updateRecordBuilder
                    .append("<br>")
                    .append(index++)
                    .append(".原检材编号为 [")
                    .append(oldMaterial.getImNo())
                    .append("] 的检材信息");
            if (!equalsName) {
                updateRecordBuilder
                        .append(" 疑似物种类由 [")
                        .append(oldMaterial.getName())
                        .append("] 更改为 [")
                        .append(name).append("]");
            }
            if (!equalsAnalysisOption) {
                updateRecordBuilder
                        .append(" 分析项目由 [")
                        .append(AnalysisOptionEnums.fromCode(oldMaterial.getAnalysisOption()).getChineseName())
                        .append("] 更改为 [")
                        .append(AnalysisOptionEnums.fromCode(analysisOption).getChineseName()).append("]");
            }
            if (!equalsDrugInfo) {
                updateRecordBuilder
                        .append(" 候选毒品列表由 [")
                        .append(oldDrugsStr)
                        .append("] 更改为 [")
                        .append(renewDrugsStr).append("]");
            }
            updateRecordBuilder.append("。");
            EntrustmentIdentificationMaterial entrustmentIdentificationMaterial = new EntrustmentIdentificationMaterial();
            entrustmentIdentificationMaterial.setId(materialId);
            entrustmentIdentificationMaterial.setName(name);
            entrustmentIdentificationMaterial.setCandidateDrugs(candidateDrugs);
            entrustmentIdentificationMaterial.setAnalysisOption(analysisOption);
            entrustmentIdentificationMaterialList.add(entrustmentIdentificationMaterial);
        }
        entrustmentIdentificationMaterialService.updateBatchById(entrustmentIdentificationMaterialList);
        // 3. 更新委托鉴定要求
        updateEntrustmentRequirement(entrustmentId, entrustment);
        // 如果确认完成，则删除鉴定事项确认书和委托书，并更新申请状态为已完成
        if (dto.getFinished()) {
            // 4.删除鉴定事项确认书和委托书
            deleteConfirmEntrustLetter(entrustment.getEntrustmentNo(), entrustmentId);
        }
        return super.update(Wrappers.<EntrustAlterApply>lambdaUpdate().eq(EntrustAlterApply::getId, dto.getId())
                .set(EntrustAlterApply::getUpdateRecord, updateRecordBuilder.toString())
                .set(dto.getFinished(), EntrustAlterApply::getStatus, EntrustAlterApplyStatus.FINISHED.getStatus()));
    }

    /**
     * 判断当前委托是否在申请中的状态
     * @param entrustId
     * @return
     */
    @Override
    public Boolean isApplying(String entrustId) {
        List<EntrustAlterApply> preApplyInfo = super.list(Wrappers.<EntrustAlterApply>lambdaQuery().eq(EntrustAlterApply::getEntrustId, entrustId));
        if (CollUtil.isNotEmpty(preApplyInfo)) {
            List<EntrustAlterApply> unfinishedList = preApplyInfo.stream().filter(e -> !e.getStatus().equals(EntrustAlterApplyStatus.FINISHED.getStatus())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(unfinishedList)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 更新鉴定要求
     * @param entrustmentId
     * @param entrustment
     */
    public void updateEntrustmentRequirement(String entrustmentId, Entrustment entrustment) {
        List<EntrustmentIdentificationMaterial> renewList = entrustmentIdentificationMaterialService.list(Wrappers.<EntrustmentIdentificationMaterial>lambdaQuery()
                .eq(EntrustmentIdentificationMaterial::getEntrustmentId, entrustmentId)
                .orderByAsc(EntrustmentIdentificationMaterial::getOrderNo));
        entrustment.setEntrustRequirement(entrustmentService.buildEntrustReq(renewList));
        entrustmentService.updateById(entrustment);
    }

    /**
     * 删除委托书和鉴定事项确认书
     * @param entrustmentNo
     * @param entrustmentId
     */
    private void deleteConfirmEntrustLetter(String entrustmentNo, String entrustmentId) {
        String identifyItemsConfirmLetterFileName = "鉴定事项确认书-" + entrustmentNo;
        // 鉴定确认书存储路径
        String identifyItemsConfirmLetterPdfFilePath = OSSDirectoryConstants.IDENTIFY_BOOK_DIRECTORY + "/" + entrustmentId + "/" + identifyItemsConfirmLetterFileName + ".pdf";
        String identifyItemsConfirmLetterWordFilePath = OSSDirectoryConstants.IDENTIFY_BOOK_DIRECTORY + "/" + entrustmentId + "/" + identifyItemsConfirmLetterFileName + ".docx";
        String entrustmentLetterFileName = "鉴定委托书" + "-" + entrustmentNo;
        // 转换临时目录中的 word 文档为 PDF
        String entrustmentLetterFileNamePdfFilePath = OSSDirectoryConstants.DOCUMENT_ENTRUSTMENT_DIRECTORY + "/" + entrustmentId + "/" + entrustmentLetterFileName + ".docx";

        try {
            ossFile.fileDelete(identifyItemsConfirmLetterWordFilePath);
            ossFile.fileDelete(identifyItemsConfirmLetterPdfFilePath);
            ossFile.fileDelete(entrustmentLetterFileNamePdfFilePath);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ValidateCodeException("删除鉴定委托书和鉴定事项确认书失败！");
        }
    }

    /**
     * 校验更新数据是否合法，并且返回委托信息
     * @param dto
     * @return
     */
    private Entrustment validUpdateInfoAndGetEntrustInfo(ApprovedUpdateEntrustDTO dto) {
        // 判断当前申请状态是否审核通过
        EntrustAlterApply entrustAlterApply = super.getById(dto.getId());
        if (entrustAlterApply == null) {
            throw new ValidateCodeException("申请记录不存在!");
        }
        DLPUser user = SecurityUtils.getUser();
        if (!entrustAlterApply.getApplicant().equals(user.getId())) {
            throw new ValidateCodeException("请勿修改其他人的申请信息！");
        }
        if (!entrustAlterApply.getStatus().equals(EntrustAlterApplyStatus.APPLY_SUCCESS.getStatus())) {
            throw new ValidateCodeException("状态不合法，当前申请状态不允许修改委托信息!");
        }
        // 状态合法，开始修改委托信息
        // 1. 修改委托案件简要
        Entrustment entrustment = entrustmentService.getById(dto.getEntrustId());
        if (entrustment == null) {
            throw new ValidateCodeException("修改的委托记录不存在！");
        }
        return entrustment;
    }

    /**
     * 填充VO信息
     * @param e
     */
    private void fillVOInfo(EntrustAlterApplyVO e) {
        e.setStatusName(EntrustAlterApplyStatus.fromStatus(e.getStatus()).getDesc());
        e.setApplicantName(commonFeignService.remoteGetUserById(e.getApplicant()).getName());
        if (StrUtil.isNotBlank(e.getReviewer())) {
            e.setReviewerName(commonFeignService.remoteGetUserById(e.getReviewer()).getName());
        }
        e.setApplyOrgName(commonFeignService.remoteGetSysOrg(e.getApplyOrgId()).getName());
    }
}




