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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.aop.annotation.DlpResultProc;
import digital.laboratory.platform.common.core.exception.ValidateCodeException;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.common.security.util.SecurityUtils;
import digital.laboratory.platform.imr.convert.DrugHandingOverApplyConvert;
import digital.laboratory.platform.imr.dto.DrugHandingOverReviewDTO;
import digital.laboratory.platform.imr.entity.DrugCaseInfo;
import digital.laboratory.platform.imr.entity.DrugHandingOverApply;
import digital.laboratory.platform.imr.entity.DrugMaterialInfo;
import digital.laboratory.platform.imr.enums.DrugHandingOverApplyStatus;
import digital.laboratory.platform.imr.enums.DrugMaterialStatus;
import digital.laboratory.platform.imr.enums.UnitEnums;
import digital.laboratory.platform.imr.mapper.DrugHandingOverApplyMapper;
import digital.laboratory.platform.imr.mapper.DrugMaterialInfoMapper;
import digital.laboratory.platform.imr.query.DrugHandingOverApplyQuery;
import digital.laboratory.platform.imr.service.DrugCaseInfoService;
import digital.laboratory.platform.imr.service.DrugHandingOverApplyService;
import digital.laboratory.platform.imr.service.DrugMaterialInfoService;
import digital.laboratory.platform.imr.vo.DrugHandingOverApplyVO;
import digital.laboratory.platform.imr.vo.DrugMaterialInfoVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author ChenJiangBao
* @description 针对表【b_drug_handing_over_apply(毒品库中关联的案事件信息)】的数据库操作Service实现
* @createDate 2025-01-08 17:30:46
*/
@Service
public class DrugHandingOverApplyServiceImpl extends ServiceImpl<DrugHandingOverApplyMapper, DrugHandingOverApply>
    implements DrugHandingOverApplyService{

    @Resource
    private DrugCaseInfoService drugCaseInfoService;

    @Resource
    private DrugMaterialInfoService drugMaterialInfoService;

    @Resource
    private DrugMaterialInfoMapper drugMaterialInfoMapper;

    /**
     * 创建毒品送缴申请-委托单位操作
     * @return
     */
    @Override
    @DlpResultProc
    public DrugHandingOverApplyVO create() {
        DLPUser user = SecurityUtils.getUser();
        DrugHandingOverApply entity = new DrugHandingOverApply();
        entity.setHandingOverUser(user.getId());
        entity.setHandingOverOrg(user.getOrgId());
        entity.setApplyDate(LocalDateTime.now());
        entity.setStatus(DrugHandingOverApplyStatus.WAIT_HANDING_OVER.getStatus());
        if (super.save(entity)) {
            return DrugHandingOverApplyConvert.entityToVO(entity);
        }
        return null;
    }

    /**
     * 根据毒品送缴申请查询条件分页查询毒品送缴申请VO对象
     *
     * @param query 查询条件
     * @return 分页后的毒品送缴申请视图对象列表
     */
    @Override
    @DlpResultProc
    public IPage<DrugHandingOverApplyVO> voPage(DrugHandingOverApplyQuery query) {
        LambdaQueryWrapper<DrugHandingOverApply> lambdaQueryWrapper = appendQueryCriteria(query);
        IPage<DrugHandingOverApplyVO> page = baseMapper.queryDrugHandingOverApplyVOPage(new Page<>(query.getCurrent(), query.getSize()), lambdaQueryWrapper);
        page.getRecords().forEach( record -> {
            record.setStatusName(DrugHandingOverApplyStatus.fromStatus(record.getStatus()).getDesc());
        });
        return page;
    }

    /**
     * 删除送缴申请
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(List<String> ids) {
        List<DrugHandingOverApply> drugHandingOverApplies = super.listByIds(ids);
        for (DrugHandingOverApply drugHandingOverApply : drugHandingOverApplies) {
            if (!drugHandingOverApply.getStatus().equals(DrugHandingOverApplyStatus.WAIT_HANDING_OVER.getStatus())) {
                throw new ValidateCodeException(String.format("id为 %s 的申请已经送缴，不能删除！", drugHandingOverApply.getId()));
            }
        }

        if (super.removeByIds(ids)) {
            List<DrugCaseInfo> drugCaseInfoList = drugCaseInfoService.list(Wrappers.<DrugCaseInfo>lambdaQuery().in(DrugCaseInfo::getApplyId, ids));
            if (CollUtil.isNotEmpty(drugCaseInfoList)) {
                List<String> caseIdList = drugCaseInfoList.stream().map(DrugCaseInfo::getId).collect(Collectors.toList());
                drugCaseInfoService.removeByIds(caseIdList);
                List<DrugMaterialInfo> drugMaterialInfos = drugMaterialInfoService.list(Wrappers.<DrugMaterialInfo>lambdaQuery().in(DrugMaterialInfo::getCaseId, caseIdList));
                if (CollUtil.isNotEmpty(drugMaterialInfos)) {
                    drugMaterialInfoService.remove(Wrappers.<DrugMaterialInfo>lambdaQuery().in(DrugMaterialInfo::getCaseId, caseIdList));
                }
            }
        } else {
            return false;
        }
        return true;
    }

    /**
     * 审核送缴申请
     *
     * @param dto
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DrugHandingOverApplyVO review(DrugHandingOverReviewDTO dto, DLPUser user) {
        DrugHandingOverApply byId = super.getById(dto.getId());
        if (byId == null) {
            throw new ValidateCodeException("数据不存在！");
        }
        if (!byId.getStatus().equals(DrugHandingOverApplyStatus.WAIT_ACCEPT.getStatus())) {
            throw new ValidateCodeException("该申请不在 [待审核] 状态！");
        }

        boolean update = super.update(Wrappers.<DrugHandingOverApply>lambdaUpdate()
                .eq(DrugHandingOverApply::getId, dto.getId())
                .set(DrugHandingOverApply::getReason, dto.getReason())
                .set(DrugHandingOverApply::getReviewer, user.getId())
                .set(DrugHandingOverApply::getReviewDate, LocalDateTime.now())
                .set(DrugHandingOverApply::getStatus,
                        dto.getIsPass() == 1 ? DrugHandingOverApplyStatus.AGREE_ACCEPT.getStatus() : DrugHandingOverApplyStatus.REJECT_ACCEPT.getStatus()
                )
        );
        if (update) {
            if (dto.getIsPass() == 1) {
                // 更新毒品检材状态
                drugMaterialInfoService.update(
                        Wrappers.<DrugMaterialInfo>lambdaUpdate()
                                .inSql(DrugMaterialInfo::getCaseId, String.format("SELECT case_id FROM b_drug_case_info WHERE apply_id = '%s'", dto.getId()))
                                .set(DrugMaterialInfo::getStatus, DrugMaterialStatus.WAIT_RECHECK.getStatus())
                );
            }
            return DrugHandingOverApplyConvert.entityToVO(super.getById(dto.getId()));
        }
        return null;
    }

    /**
     * 提交送缴申请
     *
     * @param applyIds
     * @return
     */
    @Override
    public boolean submit(List<String> applyIds) {
        List<DrugHandingOverApply> drugHandingOverApplies = super.listByIds(applyIds);
        Map<String, DrugHandingOverApply> handingOverApplyMap = drugHandingOverApplies.stream().collect(Collectors.toMap(DrugHandingOverApply::getId, Function.identity()));

        applyIds.forEach( applyId -> {
            DrugHandingOverApply preInfo = handingOverApplyMap.get(applyId);
            if (preInfo == null) {
                throw new ValidateCodeException("数据不存在！");
            }
            if (!preInfo.getStatus().equals(DrugHandingOverApplyStatus.WAIT_HANDING_OVER.getStatus())) {
                throw new ValidateCodeException("该申请不在 [待提交] 状态！");
            }
        });

        return super.update(Wrappers.<DrugHandingOverApply>lambdaUpdate()
                .in(DrugHandingOverApply::getId, applyIds)
                .set(DrugHandingOverApply::getHandingOverDate, LocalDateTime.now())
                .set(DrugHandingOverApply::getStatus, DrugHandingOverApplyStatus.WAIT_ACCEPT.getStatus())
        );
    }


    @Override
    public boolean finish(String applyId) {
        // 获取申请记录，如果没有找到则抛出异常
        DrugHandingOverApply handingOverApply = super.getById(applyId);
        if (handingOverApply == null) {
            throw new ValidateCodeException(String.format("id为 %s 的申请在系统中查询不到！", applyId));
        }

        // 检查申请的状态，如果状态不是“确认收样”，则抛出异常
        if (!DrugHandingOverApplyStatus.AGREE_ACCEPT.getStatus().equals(handingOverApply.getStatus())) {
            throw new ValidateCodeException("该申请还未确认收样！");
        }

        // 获取该申请的检材列表
        List<DrugMaterialInfoVO> drugMaterialVOList = drugMaterialInfoMapper.getDrugMaterialVO(
                Wrappers.<DrugMaterialInfo>query().eq("dc.apply_id", applyId)
        );

        // 初始化固体和液体的总重/总量
        BigDecimal solidTotalWeight = BigDecimal.ZERO;
        BigDecimal liquidTotalVolume = BigDecimal.ZERO;

        // 遍历检材列表，进行分类并计算总重或总量
        for (DrugMaterialInfoVO material : drugMaterialVOList) {
            String unit = material.getRecheckUnit(); // 获取单位
            BigDecimal massVolume = material.getRecheckMassVolume(); // 获取质量或体积

            // 根据单位进行换算并累加
            if (UnitEnums.UNIT_SOLID_G.getCode().equals(unit)) {
                // 如果单位是g，直接加到总重中
                solidTotalWeight = solidTotalWeight.add(massVolume);
            } else if (UnitEnums.UNIT_SOLID_MG.getCode().equals(unit)) {
                // 如果单位是mg，将其转换为g再加到总重中 (1g = 1000mg)
                solidTotalWeight = solidTotalWeight.add(massVolume.divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP));
            } else if (UnitEnums.UNIT_LIQUID_L.getCode().equals(unit)) {
                // 如果单位是l，直接加到总量中
                liquidTotalVolume = liquidTotalVolume.add(massVolume);
            } else if (UnitEnums.UNIT_LIQUID_ML.getCode().equals(unit)) {
                // 如果单位是ml，将其转换为l再加到总量中 (1l = 1000ml)
                liquidTotalVolume = liquidTotalVolume.add(massVolume.divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP));
            }
        }

        // 更新申请记录的固体总重和液体总量
        handingOverApply.setSolidTotalWeight(solidTotalWeight);
        handingOverApply.setLiquidTotalVolume(liquidTotalVolume);

        // 更新申请状态为“完成”
        handingOverApply.setStatus(DrugHandingOverApplyStatus.FINISH.getStatus());

        // 更新数据库中的申请记录
        return super.updateById(handingOverApply);
    }


    /**
     * 判断申请中是否有待入库或者出库待归还的检材
     * @param applyId
     * @return
     */
    @Override
    public boolean whetherAllowInbound(String applyId) {
        DrugHandingOverApply handingOverApply = super.getById(applyId);
        if (handingOverApply == null) {
            throw new ValidateCodeException(String.format("id为 %s 的申请在系统中查询不到！", applyId));
        }
        // 检查申请的状态，如果状态不是“确认收样”，则抛出异常
        if (DrugHandingOverApplyStatus.FINISH.getStatus().equals(handingOverApply.getStatus())) {
            throw new ValidateCodeException("该申请已经完成收样！不能在次操作入库！");
        }
        if (!DrugHandingOverApplyStatus.AGREE_ACCEPT.getStatus().equals(handingOverApply.getStatus())) {
            throw new ValidateCodeException("该申请还未确认收样！");
        }

        List<DrugMaterialInfoVO> drugMaterialVOList = drugMaterialInfoMapper.getDrugMaterialVO(Wrappers.<DrugMaterialInfo>query()
                .eq("dc.apply_id", applyId)
                .in("dm.status", DrugMaterialStatus.RECHECKED.getStatus(), DrugMaterialStatus.OUTBOUND.getStatus(), DrugMaterialStatus.WAIT_INBOUND.getStatus())
        );
        return CollUtil.isNotEmpty(drugMaterialVOList);
    }

    /**
     * 根据给定的查询条件构建LambdaQueryWrapper查询对象
     *
     * @param query 查询条件对象，包含时间范围类型、用户查询类型等
     * @return 构建的LambdaQueryWrapper查询对象
     */
    private LambdaQueryWrapper<DrugHandingOverApply> appendQueryCriteria(DrugHandingOverApplyQuery query) {
        DLPUser user = SecurityUtils.getUser();
        Integer timeRangeType = query.getTimeRangeType();
        Integer userQueryType = query.getUserQueryType();
        LambdaQueryWrapper<DrugHandingOverApply> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(!user.isStaff(), DrugHandingOverApply::getHandingOverOrg, user.getOrgId());
        // 受理单位不需要看待提交的申请
        lambdaQueryWrapper.and(
                user.isStaff(),
                wrapper ->
                        wrapper.ne(DrugHandingOverApply::getStatus, DrugHandingOverApplyStatus.WAIT_HANDING_OVER.getStatus())
                                .or()
                                .eq(DrugHandingOverApply::getHandingOverUser, user.getId())
        );
        if (timeRangeType != null) {
            if (timeRangeType == 1) {
                lambdaQueryWrapper.ge(query.getStartDate() != null, DrugHandingOverApply::getApplyDate, query.getStartDate())
                        .le(query.getEndDate() != null, DrugHandingOverApply::getApplyDate, query.getEndDate());
            } else if (timeRangeType == 2) {
                lambdaQueryWrapper.ge(query.getStartDate() != null, DrugHandingOverApply::getHandingOverDate, query.getStartDate())
                        .le(query.getEndDate() != null, DrugHandingOverApply::getHandingOverDate, query.getEndDate());
            }
        }

        if (userQueryType != null) {
            if (userQueryType == 1) {
                lambdaQueryWrapper.eq(StrUtil.isNotBlank(query.getUserId()), DrugHandingOverApply::getHandingOverUser, query.getUserId());
            } else if (userQueryType == 2) {
                lambdaQueryWrapper.eq(StrUtil.isNotBlank(query.getUserId()), DrugHandingOverApply::getReviewer, query.getUserId());
            }
        }
        return lambdaQueryWrapper;
    }
}




