package org.dromara.web.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.StringUtil;
import org.dromara.common.core.constant.BizConst;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.system.domain.*;
import org.dromara.web.domain.vo.NutritionEvaluationVo;
import org.dromara.web.domain.vo.NutritionScreeningVo;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.domain.vo.SysDiseaseLabelVo;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysDiseaseLabelService;
import org.dromara.web.domain.*;
import org.dromara.web.domain.bo.HospitalRecordBo;
import org.dromara.web.domain.vo.*;
import org.dromara.web.domain.vo.hospitalRecord.*;
import org.dromara.web.mapper.*;
import org.dromara.web.service.IHospitalRecordService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class HospitalRecordServiceImpl implements IHospitalRecordService {

    private final SysUserMapper userMapper;

    private final SysDeptMapper sysDeptMapper;

    private final TreatmentUserMapper treatmentUserMapper;

    private final ISysDictDataService dictDataService;

    private final NutritionDiagnosisMapper diagnosisMapper;

    private final HospitalMealPlanMapper hospitalMealPlanMapper;

    private final HospitalMealRecipeMapper hospitalMealRecipeMapper;

    private final DailyMealPlanMapper dailyMealPlanMapper;

    private final DailyMealRecipeMapper dailyMealRecipeMapper;

    private final NutritionScreeningMapper nutritionScreeningMapper;

    private final NutritionEvaluationMapper nutritionEvaluationMapper;

    private final SettlementMapper settlementMapper;

    private final EnteralNutritionMapper enteralNutritionMapper;

    private final SysScreeningAssessmentConfigMapper sysScreeningAssessmentConfigMapper;

    private final ISysDiseaseLabelService diseaseLabelService;

    @Override
    public HospitalRecordVo queryHospitalRecordList(HospitalRecordBo bo) {
        HospitalRecordVo recordVo = new HospitalRecordVo();
        /*获取所有用户信息*/
        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));

        /*获取所有用户信息*/
        List<SysDept> deptList = sysDeptMapper.selectList(Wrappers.lambdaQuery(SysDept.class).select(SysDept::getDeptId, SysDept::getDeptName));
        Map<Long, String> deptMap = deptList.stream().collect(Collectors.toMap(k1 -> k1.getDeptId(), k2 -> String.valueOf(k2.getDeptName()), (k1, k2) -> k1));

        /*获取支付类型字典*/
        Map<String, List<SysDictDataVo>> dictMap = dictDataService.selectGroupByType(List.of(BizConst.PAYMENT_STATUS, BizConst.FEE_TYPE)).getData();
        Map<String, String> feeTypeMap = dictMap.get(BizConst.FEE_TYPE).stream().collect(Collectors.toMap(k1 -> k1.getDictValue(), k2 -> k2.getDictLabel(), (k1, k2) -> k1));
        if (null != bo.getPatientId()) {
            TreatmentUser treatmentUser = treatmentUserMapper.selectById(bo.getPatientId());
            if (null != treatmentUser) {
                recordVo.setDeptId(treatmentUser.getDoorId());
                recordVo.setDeptName(deptMap.get(treatmentUser.getDoorId()));
                recordVo.setCreateTime(treatmentUser.getCreateTime());
                recordVo.setCreateBy(treatmentUser.getCreateBy());
                recordVo.setCreateByUser(userMap.get(treatmentUser.getCreateBy()));
            }
        }

        /*获取就诊记录中 营养诊断明细*/
        LambdaQueryWrapper<NutritionDiagnosis> nutritionDiagnosisLambdaQueryWrapper = buildQueryWrapper(bo, NutritionDiagnosis.class);
        List<NutritionDiagnosisVo> diagnosisVoList = diagnosisMapper.selectVoList(nutritionDiagnosisLambdaQueryWrapper);

        List<RecordDiagnosisVo> recordDiagnosisVoList = null;
        RecordDiagnosisVo recordDiagnosisVo = null;
        if (CollUtil.isNotEmpty(diagnosisVoList)) {
            recordDiagnosisVoList = new ArrayList<>();
            String labelIdsStr = null;
            List<String> labelNames = null;
            for (NutritionDiagnosisVo diagnosisVo : diagnosisVoList) {
                recordDiagnosisVo = new RecordDiagnosisVo();
                BeanUtils.copyProperties(diagnosisVo, recordDiagnosisVo);
                recordDiagnosisVo.setCreateByUser(userMap.get(diagnosisVo.getCreateBy()));
                labelIdsStr = diagnosisVo.getDiagnosisLableId();
                // 处理产品标签
                if (StringUtils.isNotBlank(labelIdsStr)) {
                    labelNames = Arrays.stream(labelIdsStr.split(",")).map(String::trim).filter(StringUtils::isNotBlank).map(labelid -> {
                        try {
                            return diseaseLabelService.queryById(Long.parseLong(labelid));
                        } catch (NumberFormatException e) {
                            return null;
                        }
                    }).filter(Objects::nonNull).map(SysDiseaseLabelVo::getLabelName).filter(StringUtils::isNotBlank).collect(Collectors.toList());

                    if (!labelNames.isEmpty()) {
                        recordDiagnosisVo.setDiagnosisLabelStr(String.join(",", labelNames));
                    }
                }
                recordDiagnosisVoList.add(recordDiagnosisVo);
            }
        }
        recordVo.setRecordDiagnosisVoList(recordDiagnosisVoList);

        /*获取就诊记录中 院内膳食*/
        LambdaQueryWrapper<HospitalMealPlan> hospitalMealPlanLambdaQueryWrapper = buildQueryWrapper(bo, HospitalMealPlan.class);
        List<HospitalMealPlanVo> hospitalMealPlanVos = hospitalMealPlanMapper.selectVoList(hospitalMealPlanLambdaQueryWrapper);
        List<RecordHospitalMealPlanVo> recordHospitalMealPlanVoList = null;
        RecordHospitalMealPlanVo recordHospitalMealPlanVo = null;
        List<HospitalMealRecipeVo> voList = null;
        if (CollUtil.isNotEmpty(hospitalMealPlanVos)) {
            recordHospitalMealPlanVoList = new ArrayList<>();
            Map<String, List<HospitalMealRecipeVo>> recipeMap = null;
            for (HospitalMealPlanVo planVo : hospitalMealPlanVos) {
                recordHospitalMealPlanVo = new RecordHospitalMealPlanVo();
                BeanUtils.copyProperties(planVo, recordHospitalMealPlanVo);
                recordHospitalMealPlanVo.setCreateByUser(userMap.get(planVo.getCreateBy()));
                voList = hospitalMealRecipeMapper.selectVoList(Wrappers.lambdaQuery(HospitalMealRecipe.class)
                    .eq(HospitalMealRecipe::getPlanId, planVo.getId()));
                if (CollUtil.isNotEmpty(voList)) {
                    recipeMap = voList.stream()
                        .collect(Collectors.groupingBy(
                            recipe -> "recipeNo" + recipe.getRecipeNo(),
                            Collectors.toList()
                        ));
                    recordHospitalMealPlanVo.setRecipeMap(recipeMap);
                }
                recordHospitalMealPlanVoList.add(recordHospitalMealPlanVo);
            }
        }
        recordVo.setRecordHospitalMealPlanVoList(recordHospitalMealPlanVoList);

        /*获取就诊记录中 日常膳食*/
        LambdaQueryWrapper<DailyMealPlan> dailyMealPlanLambdaQueryWrapper = buildQueryWrapper(bo, DailyMealPlan.class);
        List<DailyMealPlanVo> dailyMealPlanVos = dailyMealPlanMapper.selectVoList(dailyMealPlanLambdaQueryWrapper);
        List<RecordDailyMealPlanVo> recordDailyMealPlanVoList = null;
        RecordDailyMealPlanVo recordDailyMealPlanVo = null;
        List<DailyMealRecipeVo> dailyMealRecipeVos = null;
        if (CollUtil.isNotEmpty(dailyMealPlanVos)) {
            recordDailyMealPlanVoList = new ArrayList<>();
            Map<String, List<DailyMealRecipeVo>> recipeMap = null;
            for (DailyMealPlanVo planVo : dailyMealPlanVos) {
                recordDailyMealPlanVo = new RecordDailyMealPlanVo();
                BeanUtils.copyProperties(planVo, recordDailyMealPlanVo);
                recordDailyMealPlanVo.setCreateByUser(userMap.get(planVo.getCreateBy()));
                dailyMealRecipeVos = dailyMealRecipeMapper.selectVoList(Wrappers.lambdaQuery(DailyMealRecipe.class)
                    .eq(DailyMealRecipe::getPlanId, planVo.getId()));
                if (CollUtil.isNotEmpty(voList)) {
                    recipeMap = dailyMealRecipeVos.stream()
                        .collect(Collectors.groupingBy(
                            recipe -> "recipeNo" + recipe.getRecipeNo(),
                            Collectors.toList()
                        ));
                    recordDailyMealPlanVo.setRecipeMap(recipeMap);
                }
                recordDailyMealPlanVoList.add(recordDailyMealPlanVo);
            }
        }
        recordVo.setRecordDailyMealPlanVoList(recordDailyMealPlanVoList);

        /*获取就诊记录中营养筛查*/
        LambdaQueryWrapper<NutritionScreening> nutritionScreeningLambdaQueryWrapper = buildQueryWrapper(bo, NutritionScreening.class);
        List<NutritionScreeningVo> nutritionScreeningVos = nutritionScreeningMapper.selectVoList(nutritionScreeningLambdaQueryWrapper);
        List<RecordScreeningVo> recordScreeningVoList = null;
        RecordScreeningVo recordScreeningVo = null;
        if (CollUtil.isNotEmpty(nutritionScreeningVos)) {
            recordScreeningVoList = new ArrayList<>();
            Set<Long> configIdList = CollUtil.newHashSet();
            nutritionScreeningVos.forEach(v -> {
                configIdList.add(v.getConfigId());
            });
            Map<Long, String> configMap = sysScreeningAssessmentConfigMapper.selectList(Wrappers.lambdaQuery(SysScreeningAssessmentConfig.class)
                .select(SysScreeningAssessmentConfig::getConfigId, SysScreeningAssessmentConfig::getName)
                .in(SysScreeningAssessmentConfig::getConfigId, configIdList)).stream().collect(Collectors.toMap(k1 -> k1.getConfigId(), k2 -> k2.getName(), (k1, k2) -> k1));
            for (NutritionScreeningVo screeningVo : nutritionScreeningVos) {
                recordScreeningVo = new RecordScreeningVo();
                BeanUtils.copyProperties(screeningVo, recordScreeningVo);
                recordScreeningVo.setCreateByUser(userMap.get(recordScreeningVo.getCreateBy()));
                recordScreeningVo.setConfigName(configMap.get(recordScreeningVo.getConfigId()));
                recordScreeningVoList.add(recordScreeningVo);
            }
        }
        recordVo.setRecordScreeningVoList(recordScreeningVoList);

        /*获取就诊记录中营养评估*/
        LambdaQueryWrapper<NutritionEvaluation> nutritionEvaluationLambdaQueryWrapper = buildQueryWrapper(bo, NutritionEvaluation.class);
        List<NutritionEvaluationVo> nutritionEvaluationVos = nutritionEvaluationMapper.selectVoList(nutritionEvaluationLambdaQueryWrapper);
        List<RecordEvaluationVo> recordEvaluationVoList = null;
        RecordEvaluationVo recordEvaluationVo = null;
        if (CollUtil.isNotEmpty(nutritionEvaluationVos)) {
            recordEvaluationVoList = new ArrayList<>();
            Set<Long> configIdList = CollUtil.newHashSet();
            nutritionEvaluationVos.forEach(v -> {
                configIdList.add(v.getConfigId());
            });
            Map<Long, String> configMap = sysScreeningAssessmentConfigMapper.selectList(Wrappers.lambdaQuery(SysScreeningAssessmentConfig.class)
                .select(SysScreeningAssessmentConfig::getConfigId, SysScreeningAssessmentConfig::getName)
                .in(SysScreeningAssessmentConfig::getConfigId, configIdList)).stream().collect(Collectors.toMap(k1 -> k1.getConfigId(), k2 -> k2.getName(), (k1, k2) -> k1));
            for (NutritionEvaluationVo evaluationVo : nutritionEvaluationVos) {
                recordEvaluationVo = new RecordEvaluationVo();
                BeanUtils.copyProperties(evaluationVo, recordEvaluationVo);
                recordEvaluationVo.setCreateByUser(userMap.get(recordEvaluationVo.getCreateBy()));
                recordEvaluationVo.setConfigName(configMap.get(recordEvaluationVo.getConfigId()));
                recordEvaluationVoList.add(recordEvaluationVo);
            }
        }
        recordVo.setRecordEvaluationVoList(recordEvaluationVoList);


        /*获取就诊记录中的处方信息*/
        LambdaQueryWrapper<Settlement> settlementLambdaQueryWrapper = buildQueryWrapper(bo, Settlement.class);
        List<SettlementVo> settlementVos = settlementMapper.selectVoList(settlementLambdaQueryWrapper);
        List<RecordSettlementVo> recordSettlementVoList = null;
        RecordSettlementVo recordSettlementVo = null;
        List<EnteralNutritionVo> enteralNutritionVoList = null;
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        if (CollUtil.isNotEmpty(settlementVos)) {
            recordSettlementVoList = new ArrayList<>();
            Map<String, List<EnteralNutritionVo>> enteralMap = null;
            for (SettlementVo settlementVo : settlementVos) {
                recordSettlementVo = new RecordSettlementVo();
                BeanUtils.copyProperties(settlementVo, recordSettlementVo);
                recordSettlementVo.setCreateByUser(userMap.get(recordSettlementVo.getCreateBy()));
                enteralNutritionVoList = enteralNutritionMapper.selectVoList(Wrappers.lambdaQuery(EnteralNutrition.class)
                    .eq(EnteralNutrition::getSettlementId, settlementVo.getId()));
                if (CollUtil.isNotEmpty(voList)) {
                    enteralMap = enteralNutritionVoList.stream()
                        .collect(Collectors.groupingBy(
                            enteral -> sdf.format(enteral.getCreateTime()) + " " + feeTypeMap.get(enteral.getPrescriptionType()),
                            Collectors.toList()
                        ));
                    recordSettlementVo.setEnteralMap(enteralMap);
                }
                recordSettlementVoList.add(recordSettlementVo);
            }

        }
        recordVo.setRecordSettlementVoList(recordSettlementVoList);


        return recordVo;
    }

    // 泛型方法，T 代表任意实体类
    private <T> LambdaQueryWrapper<T> buildQueryWrapper(HospitalRecordBo bo, Class<T> entityClass) {
        LambdaQueryWrapper<T> lqw = Wrappers.lambdaQuery(entityClass);

        List<SysUser> userList = userMapper.selectList(Wrappers.lambdaQuery(SysUser.class).select(SysUser::getUserId, SysUser::getUserName));
        Map<String, Long> userMap = userList.stream().collect(Collectors.toMap(k1 -> String.valueOf(k1.getUserName()), k2 -> k2.getUserId(), (k1, k2) -> k1));
        List<Date> dateRange = bo.getDateRange();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 公共查询条件（所有实体类通用的字段）
        lqw.orderByAsc(getField(entityClass, "id")); // 动态获取主键字段
        lqw.eq(StringUtils.isNotBlank(bo.getType()), getField(entityClass, "type"), bo.getType());
        lqw.eq(bo.getPatientId() != null, getField(entityClass, "patientId"), bo.getPatientId());
//        lqw.eq(bo.getDeptId() != null, getField(entityClass, "deptId"), bo.getDeptId());
        if (StringUtil.isNotBlank(bo.getSearchValue())) {
            lqw.and(wrapper -> wrapper
                .like(getField(entityClass, "createBy"), userMap.get(bo.getSearchValue()))
                .or()
                .like(getField(entityClass, "outpatientNo"), bo.getSearchValue()));

        }

        // 日期范围查询（
        if (null != dateRange && dateRange.size() == 2) {
            String startTime = sdf.format(dateRange.get(0)) + " 00:00:00";  // 开始时间
            String endTime = sdf.format(dateRange.get(1)) + " 23:59:59";    // 结束时间
            if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
                lqw.between(getField(entityClass, "createTime"), startTime, endTime);
            }
        }
        return lqw;
    }

    // 统一获取字段的方法
    private <T> SFunction<T, ?> getField(Class<T> entityClass, String fieldName) {
        return EntityFieldRegistry.getField(entityClass, fieldName);
    }

}
