package org.dromara.web.service.impl;

import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.constant.BizConst;
import org.dromara.common.core.enums.biz.CheckStatus;
import org.dromara.common.core.enums.biz.FeeType;
import org.dromara.common.core.enums.biz.PaymentStatus;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.system.domain.SysDept;
import org.dromara.system.domain.SysUser;
import org.dromara.system.mapper.SysDeptMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.*;
import org.dromara.web.domain.bo.SettlementBo;
import org.dromara.web.domain.vo.*;
import org.dromara.web.mapper.*;
import org.dromara.web.service.ISettlementService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 结算管理Service业务层处理
 *
 * @author Lion Li
 * @date 2025-07-22
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SettlementServiceImpl implements ISettlementService {

    private final SettlementMapper baseMapper;

    private final SysDeptMapper deptMapper;

    private final SysUserMapper userMapper;

    private final EnteralNutritionMapper enteralNutritionMapper;

    private final NutritionEvaluationMapper evaluationMapper;

    private final NutritionScreeningMapper screeningMapper;

    private final ProductNutritionMapper productNutritionMapper;

    private final HospitalMealPlanMapper mealPlanMapper;

    private final HospitalMealRecipeMapper mealRecipeMapper;

    /**
     * 查询结算管理
     *
     * @param id 主键
     * @return 结算管理
     */
    @Override
    public SettlementVo queryById(Long id) {
        SettlementVo settlementVo = baseMapper.selectVoById(id);
        List<SysUser> userList = userMapper.selectList(Wrappers.lambdaQuery(SysUser.class).select(SysUser::getUserId, SysUser::getUserName));
        Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(k1 -> k1.getUserId(), k2 -> String.valueOf(k2.getUserName()), (k1, k2) -> k1));
        if (null != settlementVo) {
            String chargeType = settlementVo.getChargeType();
            List<EnteralNutritionVo> enteralNutritionVoList = enteralNutritionMapper.selectVoList(
                new LambdaQueryWrapper<EnteralNutrition>()
                    .eq(EnteralNutrition::getSettlementId, settlementVo.getId()));

            if (CollUtil.isNotEmpty(enteralNutritionVoList)) {
                // 提获取所有需要的产品营养信息
                Set<Long> productIds = enteralNutritionVoList.stream()
                    .map(EnteralNutritionVo::getNutritionProductId)
                    .collect(Collectors.toSet());
                Map<Long, ProductNutrition> productNutritionMap = productNutritionMapper.selectBatchIds(productIds)
                    .stream()
                    .collect(Collectors.toMap(ProductNutrition::getId, Function.identity()));

                // 处理价格设置
                for (EnteralNutritionVo nutritionVo : enteralNutritionVoList) {
                    nutritionVo.setCreateByName(userMap.get(nutritionVo.getCreateBy()));
                    ProductNutrition productNutrition = productNutritionMap.get(nutritionVo.getNutritionProductId());

                    if (productNutrition != null) {
                        BigDecimal price = FeeType.PRE_PACKAGED_PRESCRIPTION.getCode().equals(chargeType)
                            ? productNutrition.getPackagePrice()
                            : productNutrition.getConfigSalePrice();
                        nutritionVo.setSalePrice(price);
                    }
                }

                // 处理处方费用计算
                if (FeeType.CONFIGURE_PRESCRIPTION.getCode().equals(chargeType)
                    || FeeType.LONG_TERM_PRESCRIPTION.getCode().equals(chargeType)) {
                    int lastGroupNo = Integer.valueOf(enteralNutritionVoList.get(enteralNutritionVoList.size() - 1).getGroupNo());
                    settlementVo.setPrescriptionFee(new BigDecimal(lastGroupNo + 1));
                }
            }

            settlementVo.setEnteralNutritionList(enteralNutritionVoList);
            List<NutritionScreeningVo> nutritionScreeningVos = screeningMapper.selectVoList(new LambdaQueryWrapper<NutritionScreening>().eq(NutritionScreening::getSettlementId, settlementVo.getId()));
            nutritionScreeningVos.forEach(v -> {
                v.setCreateByName(userMap.get(v.getCreateBy()));
            });
            settlementVo.setNutritionScreeningList(nutritionScreeningVos);
            List<NutritionEvaluationVo> nutritionEvaluationVos = evaluationMapper.selectVoList(new LambdaQueryWrapper<NutritionEvaluation>().eq(NutritionEvaluation::getSettlementId, settlementVo.getId()));
            nutritionEvaluationVos.forEach(v -> {
                v.setCreateByName(userMap.get(v.getCreateBy()));
            });
            settlementVo.setNutritionEvaluationList(nutritionEvaluationVos);

            List<HospitalMealPlanVo> hospitalMealPlanVos = mealPlanMapper.selectVoList(new LambdaQueryWrapper<HospitalMealPlan>().eq(HospitalMealPlan::getSettlementId, settlementVo.getId()));
            if (CollUtil.isNotEmpty(hospitalMealPlanVos)) {
                HospitalMealPlanVo planVo = hospitalMealPlanVos.get(0);
                List<HospitalMealRecipeVo> hospitalMealRecipeVos = mealRecipeMapper.selectVoList(new LambdaQueryWrapper<HospitalMealRecipe>().eq(HospitalMealRecipe::getPlanId, planVo.getId()));
                hospitalMealRecipeVos.forEach(v -> {
                    v.setCreateByName(userMap.get(v.getCreateBy()));
                });
                settlementVo.setRecommendStartDate(planVo.getRecommendStartDate());
                settlementVo.setRecommendEndDate(planVo.getRecommendEndDate());
                settlementVo.setHospitalMealRecipeList(hospitalMealRecipeVos);
            }
        }
        return settlementVo;
    }

    /**
     * 分页查询结算管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 结算管理分页列表
     */
    @Override
    public TableDataInfo<SettlementVo> queryPageList(SettlementBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Settlement> lqw = buildQueryWrapper(bo);
        Page<SettlementVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<SettlementVo> records = result.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            Set<Long> deptList = CollUtil.newHashSet();
            records.forEach(v -> {
                deptList.add(v.getDoorId());
            });
            Map<Long, String> deptMap = deptMapper.selectList(Wrappers.lambdaQuery(SysDept.class)
                .select(SysDept::getDeptId, SysDept::getDeptName)
                .in(SysDept::getDeptId, deptList)).stream().collect(Collectors.toMap(k1 -> k1.getDeptId(), k2 -> k2.getDeptName(), (k1, k2) -> k1));
            records.forEach(v -> {
                v.setPatientDepartment(deptMap.get(v.getDoorId()));
            });
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的结算管理列表
     *
     * @param bo 查询条件
     * @return 结算管理列表
     */
    @Override
    public List<SettlementVo> queryList(SettlementBo bo) {
        LambdaQueryWrapper<Settlement> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Settlement> buildQueryWrapper(SettlementBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Settlement> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(Settlement::getId);
        lqw.eq(bo.getOrderTime() != null, Settlement::getOrderTime, bo.getOrderTime());
        lqw.eq(StringUtils.isNotBlank(bo.getVisitType()), Settlement::getVisitType, bo.getVisitType());
        lqw.eq(StringUtils.isNotBlank(bo.getChargeType()), Settlement::getChargeType, bo.getChargeType());
        lqw.eq(bo.getPatientId() != null, Settlement::getPatientId, bo.getPatientId());
        lqw.eq(bo.getDoorId() != null, Settlement::getDoorId, bo.getDoorId());
        lqw.like(StringUtils.isNotBlank(bo.getPatientName()), Settlement::getPatientName, bo.getPatientName());
        lqw.eq(StringUtils.isNotBlank(bo.getPatientNo()), Settlement::getPatientNo, bo.getPatientNo());
        lqw.eq(bo.getReceivableAmount() != null, Settlement::getReceivableAmount, bo.getReceivableAmount());
        lqw.eq(StringUtils.isNotBlank(bo.getPaymentMethod()), Settlement::getPaymentMethod, bo.getPaymentMethod());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Settlement::getStatus, bo.getStatus());
        lqw.eq(Settlement::getPaymentStatus, PaymentStatus.UNPAID.getCode());//待收费列表只查询未支付订单
        lqw.eq(Settlement::getCheckStatus, CheckStatus.STATUS_TWO.getCode());//结算管理查询已经审核通过的处方
        lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
            Settlement::getOrderTime, params.get("beginTime"), params.get("endTime"));
        return lqw;
    }

    /**
     * 新增结算管理
     *
     * @param bo 结算管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SettlementBo bo) {
        Settlement add = MapstructUtils.convert(bo, Settlement.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return true;
    }

    /**
     * 修改结算管理
     *
     * @param bo 结算管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SettlementBo bo) {
        Settlement update = MapstructUtils.convert(bo, Settlement.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public TableDataInfo<SettlementVo> queryCheckRecipePageList(SettlementBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Settlement> lqw = buildCheckRecipeQueryWrapper(bo);
        Page<SettlementVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<SettlementVo> records = result.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            Set<Long> deptList = CollUtil.newHashSet();
            Set<Long> userList = CollUtil.newHashSet();
            records.forEach(v -> {
                deptList.add(v.getDoorId());
                userList.add(v.getCreateBy());
            });
            Map<Long, String> deptMap = deptMapper.selectList(Wrappers.lambdaQuery(SysDept.class)
                .select(SysDept::getDeptId, SysDept::getDeptName)
                .in(SysDept::getDeptId, deptList)).stream().collect(Collectors.toMap(k1 -> k1.getDeptId(), k2 -> k2.getDeptName(), (k1, k2) -> k1));

            Map<Long, String> userMap = userMapper.selectList(Wrappers.lambdaQuery(SysUser.class)
                .select(SysUser::getUserId, SysUser::getUserName)
                .in(SysUser::getUserId, userList)).stream().collect(Collectors.toMap(k1 -> k1.getUserId(), k2 -> k2.getUserName(), (k1, k2) -> k1));
            List<EnteralNutritionVo> enteralNutritionVoList = null;
            for (SettlementVo record : records) {
                enteralNutritionVoList = enteralNutritionMapper.selectVoList(new LambdaQueryWrapper<EnteralNutrition>().eq(EnteralNutrition::getSettlementId, record.getId()));
                String recipeDetail = enteralNutritionVoList.stream()
                    .map(EnteralNutritionVo::getNutritionProduct) // 获取每个对象的nutritionProduct字段
                    .filter(product -> product != null) // 过滤掉空值
                    .collect(Collectors.joining(", ")); // 用逗号和空格拼接

                record.setPatientDepartment(deptMap.get(record.getDoorId()));
                record.setRecipeDetail(recipeDetail);
                record.setCreateByUser(userMap.get(record.getCreateBy()));
//                record.setUpdateByUser(userMap.get(record.getUpdateBy()));
            }
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的结算管理列表
     *
     * @param bo 查询条件
     * @return 结算管理列表
     */
    @Override
    public List<SettlementVo> queryCheckRecipeList(SettlementBo bo) {
        LambdaQueryWrapper<Settlement> lqw = buildCheckRecipeQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Settlement> buildCheckRecipeQueryWrapper(SettlementBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Settlement> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(Settlement::getCreateTime);
        lqw.eq(bo.getOrderTime() != null, Settlement::getOrderTime, bo.getOrderTime());
        lqw.eq(bo.getCheckStatus() != null && !CheckStatus.STATUS_NINE.getCode().equals(bo.getCheckStatus()), Settlement::getCheckStatus, bo.getCheckStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getVisitType()), Settlement::getVisitType, bo.getVisitType());
        lqw.eq(StringUtils.isNotBlank(bo.getChargeType()), Settlement::getChargeType, bo.getChargeType());
        lqw.eq(bo.getDoorId() != null, Settlement::getDoorId, bo.getDoorId());
        lqw.eq(StringUtils.isNotBlank(bo.getPatientNo()), Settlement::getPatientNo, bo.getPatientNo());
        lqw.eq(Settlement::getStatus, PaymentStatus.UNPAID.getCode());
        lqw.in(Settlement::getChargeType,
            FeeType.PRE_PACKAGED_PRESCRIPTION.getCode(),
            FeeType.CONFIGURE_PRESCRIPTION.getCode(),
            FeeType.LONG_TERM_PRESCRIPTION.getCode());
        return lqw;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Settlement entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除结算管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
