package com.kcim.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.kcim.common.constants.Constant;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.constants.ParameterConstant;
import com.kcim.common.constants.SplitConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.*;
import com.kcim.dao.repository.AccountingRepository;
import com.kcim.dao.repository.ResponsibilityRepository;
import com.kcim.dao.repository.ShareParamValueRepository;
import com.kcim.service.AllocationQueryService;
import com.kcim.service.CenterService;
import com.kcim.service.IncomeCollectionService;
import com.kcim.service.StandardReportService;
import com.kcim.vo.*;
import com.kcim.vo.HospitalDeptCostAllocationVO;
import com.kcim.web.reponse.ComputeProfitCollectResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description:
 * @author: Wang.YS
 * @create: 2024-03-19 11:10
 **/
@Service("StandardReportService")
@Slf4j
@AllArgsConstructor
public class StandardReportServiceImpl implements StandardReportService {
    private static final String AMOUNT_FIELD = "amount";
    private static final String PERCENT_FIELD = "percent" ;

    ResponsibilityRepository responsibilityRepository;

    AllocationQueryService allocationQueryService;

    CenterService centerService;

    AccountingRepository accountingRepository;

    IncomeCollectionService incomeCollectionService;

    ShareParamValueRepository shareParamValueRepository;
    
    /**
     * 科室直接成本表（医疗成本）
     * @param computeDate 核算年月
     * @return
     */
    @Override
    public List<DeptDirectMedicalCostVO> getDeptDirectMedicalCost(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;
        //获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getCostByDate(UserContext.getCurrentLoginHospId(), year, month, NumberConstant.ONE);
        if(CollectionUtils.isEmpty(allocationQueryList)){
            return new ArrayList<>();
        }
        //获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap = new HashMap<>();
        //转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectMedicalCostVO(deptDirectMedicalCostMap,allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<DeptDirectMedicalCostVO> deptDirectMedicalCostList = deptDirectMedicalCostMap.values().stream().collect(Collectors.toList());
        //创建医疗业务成本合计
        DeptDirectMedicalCostVO medicalBusinessTotal = createSubtotalVo(deptDirectMedicalCostList.get(NumberConstant.ZERO), "医疗业务成本合计", DeptDirectMedicalCostVO.class);
        //创建总计
        DeptDirectMedicalCostVO grandTotal = createSubtotalVo(deptDirectMedicalCostList.get(NumberConstant.ZERO), "总计", DeptDirectMedicalCostVO.class);
        //按responsibilitySort正序排序
        deptDirectMedicalCostList.sort(Comparator.comparing(DeptDirectMedicalCostVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));
        // 按标准分级分组
        Map<String, List<DeptDirectMedicalCostVO>> shareLevelGroup = deptDirectMedicalCostList.stream().collect(Collectors.groupingBy(DeptDirectMedicalCostVO::getStandardShareLevel));
        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort,Comparator.nullsLast(Comparator.reverseOrder())));
        // 创建各层级小计并按正确顺序插入
        List<DeptDirectMedicalCostVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<DeptDirectMedicalCostVO> deptDirectMedicalCostVOS = shareLevelGroup.get(shareLevel.getCode());
            if(CollectionUtils.isEmpty(deptDirectMedicalCostVOS)){
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(deptDirectMedicalCostVOS);
            // 创建小计对象
            DeptDirectMedicalCostVO subtotalVo = createSubtotalVo(deptDirectMedicalCostVOS.get(NumberConstant.ZERO),String.format("%s小计", shareLevel.getName()), DeptDirectMedicalCostVO.class);
            //将科室的金额加到小计对象中
            deptDirectMedicalCostVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 如果属于医疗业务成本的科室，则小计的金额加到医疗业务成本
            if(NumberConstant.ONE_S.equals(shareLevel.getValue())){
                addBigDecimalFields(subtotalVo, medicalBusinessTotal);
            }
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
            // 医疗业务成本加入到医疗辅助类小计后面
            if(NumberConstant.TWO_S.equals(shareLevel.getCode())){
                result.add(medicalBusinessTotal);
            }
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 科室直接成本表（全成本）
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<DeptFullDirectCostVO> getDeptFullDirectCost(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;
        
        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getCostByDate(UserContext.getCurrentLoginHospId(), year, month, NumberConstant.ONE);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String, DeptFullDirectCostVO> reportMap = new HashMap<>();
        // 转换为DeptDirectAllCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectAllCostVO(reportMap, allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<DeptFullDirectCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(DeptFullDirectCostVO::getResponsibilitySort, Comparator.nullsLast(Comparator.naturalOrder())));
        // 按标准分级分组
        Map<String, List<DeptFullDirectCostVO>> shareLevelGroup = reportList.stream().collect(Collectors.groupingBy(DeptFullDirectCostVO::getStandardShareLevel));
        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort, Comparator.nullsLast(Comparator.reverseOrder())));
        //创建医疗业务成本合计
        DeptFullDirectCostVO medicalBusinessTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "医疗业务成本合计", DeptFullDirectCostVO.class);
        //创建总计
        DeptFullDirectCostVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", DeptFullDirectCostVO.class);
        // 创建各层级小计并按正确顺序插入
        List<DeptFullDirectCostVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<DeptFullDirectCostVO> reportVOS = shareLevelGroup.get(shareLevel.getCode());
            if (CollectionUtils.isEmpty(reportVOS)) {
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(reportVOS);
            // 创建小计对象
            DeptFullDirectCostVO subtotalVo = createSubtotalVo(reportVOS.get(NumberConstant.ZERO),String.format("%s小计", shareLevel.getName()), DeptFullDirectCostVO.class);
            //将科室的金额加到小计对象中
            reportVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 如果属于医疗业务成本的科室，则小计的金额加到医疗业务成本
            if(NumberConstant.ONE_S.equals(shareLevel.getValue())){
                addBigDecimalFields(subtotalVo, medicalBusinessTotal);
            }
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
            // 医疗业务成本加入到医疗辅助类小计后面
            if(NumberConstant.TWO_S.equals(shareLevel.getCode())){
                result.add(medicalBusinessTotal);
            }
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 获取科室成本明细数据
     * @param computeDate 核算年月
     * @return
     */
    @Override
    public List<ClinicalDeptMedicalCostVO> getClinicalDeptMedicalCost(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;
        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        // 处理 allocationQueryList 数据
        Map<String, ClinicalDeptMedicalCostVO> reportMap = new HashMap<>();
        // 添加科室成本明细（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptCostDetailVO(reportMap, allocationQuery, standCostDictMaps);
        }
        // 转成List便于处理
        List<ClinicalDeptMedicalCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());
        // 创建合计对象
        ClinicalDeptMedicalCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO),"科室全成本合计",ClinicalDeptMedicalCostVO.class);
        //将科室的金额加到合计对象中
        reportList.forEach(item -> addBigDecimalFields(item, subtotalVo));
        // 合计加到列表最后面
        reportList.add(subtotalVo);
        return reportList;
    }

    /**
     * 获取临床服务类科室全成本报表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<ClinicalDeptFullCostVO> getClinicalDeptFullCost(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;

        // 获取科室直接成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            return new ArrayList<>();
        }

        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String, ClinicalDeptFullCostVO> reportMap = new HashMap<>();

        // 转换为ClinicalDeptFullCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addClinicalDeptFullCostVO(reportMap, allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<ClinicalDeptFullCostVO> reportList = reportMap.values().stream().collect(Collectors.toList());

        // 创建合计对象
        ClinicalDeptFullCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO), "科室全成本合计", ClinicalDeptFullCostVO.class);

        // 将科室的金额加到合计对象中
        reportList.forEach(item -> addBigDecimalFields(item, subtotalVo));

        // 合计加到列表最后面
        reportList.add(subtotalVo);

        return reportList;
    }

    /**
     * 获取医院临床服务类科室全成本构成分析表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public ComputeProfitCollectResponse getClinicalDeptFullCostAnalysis(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        //获取科室收入
        List<IncomeCollection> responsibilityIncomeList = incomeCollectionService.getResponsibilitiesAccounts(year, month, UserContext.getCurrentLoginHospId());
        if (CollectionUtils.isEmpty(responsibilityIncomeList)) {
            throw new CostException("医院未归集本月收入数据");
        }
        Map<String, BigDecimal> responsibilityIncomeMap = responsibilityIncomeList.stream().collect(Collectors.toMap(IncomeCollection::getResponsibilityCode, IncomeCollection::getAmount));
        //获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        Map<String, List<ShareParamValue>> responsibilityParamValueMap = shareParamValueList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
        //获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap = new HashMap<>();
        //转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addDeptDirectMedicalCostVO(deptDirectMedicalCostMap,allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<DeptDirectMedicalCostVO> reportList = deptDirectMedicalCostMap.values().stream().collect(Collectors.toList());
        // 创建合计对象
        DeptDirectMedicalCostVO subtotalVo = createSubtotalVo(reportList.get(NumberConstant.ZERO), "科室合计", DeptDirectMedicalCostVO.class);
        subtotalVo.setResponsibilityCode("deptSubtotal");
        for (DeptDirectMedicalCostVO item : reportList) {
            //计算科室的收入及损益+床日成本及诊次成本
            calcDeptExpandCost(item, responsibilityIncomeMap, responsibilityParamValueMap, visitsBedDaysParamCode);
            // 将科室的金额加到合计对象中
            addBigDecimalFields(item, subtotalVo);
        }
        // 合计加到列表最后面
        reportList.add(subtotalVo);

        // 创建成本项目列表
        List<String> costItems = Arrays.asList(
                "人员经费", "卫生材料费", "药品费", "固定资产折旧费", "无形资产摊销费",
                "提取医疗风险基金", "其他医疗费用", "科室全成本合计","科室收入","收入-成本","床日成本","诊次成本"
        );
        //不要计算占比的项目列表
        List<String> noPercentCostItems = Arrays.asList(
                "科室收入","收入-成本","床日成本","诊次成本"
        );

        // 创建结果列表
        List<ReportFormCustomVo> resultData = new ArrayList<>();
        List<CommonResponsibilityReportVo> titleList = new ArrayList<>();

        // 提取科室名称作为列标题
        for (DeptDirectMedicalCostVO dept : reportList) {
            CommonResponsibilityReportVo title = new CommonResponsibilityReportVo();
            title.setResponsibilityName(dept.getResponsibilityName());
            title.setResponsibilityCode(dept.getResponsibilityCode());
            title.setSort(dept.getResponsibilitySort());
            //添加子级标题
            addCommonResponsibilityChild(title);
            titleList.add(title);
        }

        // 遍历每个成本项目(列转行)
        for (String costItem : costItems) {
            ReportFormCustomVo itemVo = new ReportFormCustomVo();
            itemVo.setReportName(costItem);
            itemVo.setData(new ArrayList<>());
            // 遍历每个科室
            for (DeptDirectMedicalCostVO dept : reportList)  {
                //金额对象
                ReportVo amountReportVo = new ReportVo();
                amountReportVo.setCode(getResponsibilityAmountCode(dept.getResponsibilityCode()));
                //占比对象
                ReportVo percentReportVo = new ReportVo();
                percentReportVo.setCode(getResponsibilityPercentCode(dept.getResponsibilityCode()));
                //获取金额
                BigDecimal deptAmount = getDeptAmount(dept, costItem);
                // 设置金额和百分比
                amountReportVo.setValue(deptAmount);
                //要显示占比的字段才计算占比
                if(!noPercentCostItems.contains(costItem)){
                    //计算百分比
                    BigDecimal percent = getPercent(deptAmount, dept.getTotal());
                    percentReportVo.setValue(percent);
                }
                // 添加金额和百分比
                itemVo.getData().add(amountReportVo);
                itemVo.getData().add(percentReportVo);
            }
            resultData.add(itemVo);
        }

        ComputeProfitCollectResponse response = new ComputeProfitCollectResponse();
        response.setTitle(titleList);
        response.setData(resultData);

        return response;
    }

    /**
     * 获取可是指定项目的金额
     * @param dept
     * @param costItem
     * @return
     */
    public  BigDecimal getDeptAmount(DeptDirectMedicalCostVO dept,String costItem) {
        BigDecimal amount = BigDecimal.ZERO;
        switch (costItem) {
            case "人员经费":
                amount = dept.getPersonnelExpense();
                break;
            case "卫生材料费":
                amount = dept.getHealthMaterialFee();
                break;
            case "药品费":
                amount = dept.getDrugFee();
                break;
            case "固定资产折旧费":
                amount =dept.getFixedAssetDepreciation();
                break;
            case "无形资产摊销费":
                amount = dept.getIntangibleAssetAmortization();
                break;
            case "提取医疗风险基金":
                amount = dept.getMedicalRiskFundExtraction();
                break;
            case "其他医疗费用":
                amount = dept.getOtherMedicalExpenses();
                break;
            case "科室全成本合计":
                amount = dept.getTotal();
                break;
            case "科室收入":
                amount = dept.getIncome();
                break;
            case "收入-成本":
                amount = dept.getProfit();
                break;
            case "诊次成本":
                amount = dept.getVisitsCost();
                break;
            case "床日成本":
                amount = dept.getBedDaysCost();
                break;
            default:
                break;
        }
        return amount;
    }

    /**
     * 计算科室的收入及损益+床日成本及诊次成本
     * @param item
     * @param responsibilityIncomeMap
     * @param responsibilityParamValueMap
     * @param visitsBedDaysParamCode
     */
    private void calcDeptExpandCost(DeptDirectMedicalCostVO item,
                                    Map<String, BigDecimal> responsibilityIncomeMap,
                                    Map<String, List<ShareParamValue>> responsibilityParamValueMap,
                                    String[] visitsBedDaysParamCode) {
        //计算科室的收入及损益
        if(responsibilityIncomeMap.containsKey(item.getResponsibilityCode())){
            item.setIncome(responsibilityIncomeMap.get(item.getResponsibilityCode()));
            item.setProfit(item.getIncome().subtract(item.getTotal()));
        }else{
            item.setIncome(BigDecimal.ZERO);
            item.setProfit(BigDecimal.ZERO);
        }
        //计算科室的床日成本及诊次成本
        if(responsibilityParamValueMap.containsKey(item.getResponsibilityCode())){
            List<ShareParamValue> shareParamValues = responsibilityParamValueMap.get(item.getResponsibilityCode());

            // 诊次分摊参数值
            BigDecimal visitParamValue = getParamValue(shareParamValues, visitsBedDaysParamCode[NumberConstant.ZERO]);
            // 床日分摊参数值
            BigDecimal bedDaysParamValue = getParamValue(shareParamValues, visitsBedDaysParamCode[NumberConstant.ONE]);
            // 计算诊次成本及床日成本
            item.setVisitsCost(getPercent(item.getTotal(),visitParamValue));
            item.setBedDaysCost(getPercent(item.getTotal(),bedDaysParamValue));
        }else{
            item.setBedDaysCost(BigDecimal.ZERO);
            item.setVisitsCost(BigDecimal.ZERO);
        }
    }


    /**
     * 获取百分比
     * @param amount
     * @param total
     * @return
     */
    public BigDecimal getPercent(BigDecimal amount,BigDecimal total){
        if(total.compareTo(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP)) == 0){
            return BigDecimal.ZERO;
        }
        return amount.divide(total,4, RoundingMode.HALF_UP);
    }

    /**
     * 获取责任中心金额字段
     * @param responsibilityCode
     * @return
     */
    public String getResponsibilityAmountCode(String responsibilityCode){
        return String.format("%s_%s", responsibilityCode, AMOUNT_FIELD);
    }

    /**
     * 获取责任中心占比字段
     * @param responsibilityCode
     * @return
     */
    public String getResponsibilityPercentCode(String responsibilityCode){
        return String.format("%s_%s", responsibilityCode, PERCENT_FIELD);
    }

    /**
     * 添加全成本构成表标题的子级标题
     * @param commonResponsibility
     */
    public void addCommonResponsibilityChild(CommonResponsibilityReportVo commonResponsibility) {
        commonResponsibility.setChild(new ArrayList<>());
        CommonResponsibilityReportVo amount=new CommonResponsibilityReportVo();
        amount.setResponsibilityCode(getResponsibilityAmountCode(commonResponsibility.getResponsibilityCode() ));
        amount.setResponsibilityName("金额");
        amount.setSort(NumberConstant.ZERO);
        commonResponsibility.getChild().add( amount);
        CommonResponsibilityReportVo percent=new CommonResponsibilityReportVo();
        percent.setResponsibilityCode(getResponsibilityPercentCode(commonResponsibility.getResponsibilityCode()));
        percent.setResponsibilityName("占比");
        percent.setSort(NumberConstant.ONE);
        commonResponsibility.getChild().add( percent);
    }

    /**
     * 添加临床服务类科室全成本明细
     * @param reportMap
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addClinicalDeptFullCostVO(Map<String, ClinicalDeptFullCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(account.getCostType());
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        ClinicalDeptFullCostVO reportVO = new ClinicalDeptFullCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            // 生成科室成本报表信息
            initDeptCostReport(reportVO, responsibility, accountType, costType, standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (costType.getValue()) {
            case "1":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setMedicalCostTotalDirect(reportVO.getMedicalCostTotalDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setMedicalCostTotalIndirect(reportVO.getMedicalCostTotalIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicalCostTotal(reportVO.getMedicalCostTotal().add(allocationQuery.getAmount()));
                break;
            case "2":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setFinancialProjectFundsDirect(reportVO.getFinancialProjectFundsDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setFinancialProjectFundsIndirect(reportVO.getFinancialProjectFundsIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setFinancialProjectFunds(reportVO.getFinancialProjectFunds().add(allocationQuery.getAmount()));
                break;
            case "3":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setNonPeerFinancialFundsDirect(reportVO.getNonPeerFinancialFundsDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setNonPeerFinancialFundsIndirect(reportVO.getNonPeerFinancialFundsIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setNonPeerFinancialFunds(reportVO.getNonPeerFinancialFunds().add(allocationQuery.getAmount()));
                break;
            case "4":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setEducationalExpensesDirect(reportVO.getEducationalExpensesDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setEducationalExpensesIndirect(reportVO.getEducationalExpensesIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setEducationalExpenses(reportVO.getEducationalExpenses().add(allocationQuery.getAmount()));
                break;
            case "5":
                if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                    reportVO.setAssetDisposalFeesDirect(reportVO.getAssetDisposalFeesDirect().add(allocationQuery.getAmount()));
                } else {
                    reportVO.setAssetDisposalFeesIndirect(reportVO.getAssetDisposalFeesIndirect().add(allocationQuery.getAmount()));
                }
                reportVO.setAssetDisposalFees(reportVO.getAssetDisposalFees().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }

        // 不是医院全成本的都是医疗全成本
        if (!NumberConstant.THREE_S.equals(costType.getExpandOne())) {
            if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
                reportVO.setMedicalTotalCostDirect(reportVO.getMedicalTotalCostDirect().add(allocationQuery.getAmount()));
            } else {
                reportVO.setMedicalTotalCostIndirect(reportVO.getMedicalTotalCostIndirect().add(allocationQuery.getAmount()));
            }
            reportVO.setMedicalTotalCost(reportVO.getMedicalTotalCost().add(allocationQuery.getAmount()));
        }

        // 医院全成本合计
        if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
            reportVO.setHospitalTotalCostDirect(reportVO.getHospitalTotalCostDirect().add(allocationQuery.getAmount()));
        } else {
            reportVO.setHospitalTotalCostIndirect(reportVO.getHospitalTotalCostIndirect().add(allocationQuery.getAmount()));
        }
        reportVO.setHospitalTotalCost(reportVO.getHospitalTotalCost().add(allocationQuery.getAmount()));
    }

    /**
     * 添加科室成本明细
     * @param reportMap 
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addDeptCostDetailVO(Map<String, ClinicalDeptMedicalCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(account.getCostType());
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        ClinicalDeptMedicalCostVO reportVO = new ClinicalDeptMedicalCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            //生成科室成本报表信息
            initDeptCostReport(reportVO, responsibility, accountType, costType, standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (accountType.getExpandOne())  {
            case "1":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setPersonnelDirectCost(reportVO.getPersonnelDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setPersonnelIndirectCost(reportVO.getPersonnelIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setPersonnelTotalCost(reportVO.getPersonnelTotalCost().add(allocationQuery.getAmount()));
                break;
            case "2":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setHealthMaterialDirectCost(reportVO.getHealthMaterialDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setHealthMaterialIndirectCost(reportVO.getHealthMaterialIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setHealthMaterialTotalCost(reportVO.getHealthMaterialTotalCost().add(allocationQuery.getAmount()));
                break;
            case "3":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setMedicineDirectCost(reportVO.getMedicineDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setMedicineIndirectCost(reportVO.getMedicineIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicineTotalCost(reportVO.getMedicineTotalCost().add(allocationQuery.getAmount()));
                break;
            case "4":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setFixedAssetDepreciationDirectCost(reportVO.getFixedAssetDepreciationDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setFixedAssetDepreciationIndirectCost(reportVO.getFixedAssetDepreciationIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setFixedAssetDepreciationTotalCost(reportVO.getFixedAssetDepreciationTotalCost().add(allocationQuery.getAmount()));
                break;
            case "5":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setIntangibleAssetAmortizationDirectCost(reportVO.getIntangibleAssetAmortizationDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setIntangibleAssetAmortizationIndirectCost(reportVO.getIntangibleAssetAmortizationIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setIntangibleAssetAmortizationTotalCost(reportVO.getIntangibleAssetAmortizationTotalCost().add(allocationQuery.getAmount()));
                break;
            case "6":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setMedicalRiskReserveDirectCost(reportVO.getMedicalRiskReserveDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setMedicalRiskReserveIndirectCost(reportVO.getMedicalRiskReserveIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setMedicalRiskReserveTotalCost(reportVO.getMedicalRiskReserveTotalCost().add(allocationQuery.getAmount()));
                break;
            case "7":
                if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
                    reportVO.setOtherMedicalExpensesDirectCost(reportVO.getOtherMedicalExpensesDirectCost().add(allocationQuery.getAmount()));
                }else{
                    reportVO.setOtherMedicalExpensesIndirectCost(reportVO.getOtherMedicalExpensesIndirectCost().add(allocationQuery.getAmount()));
                }
                reportVO.setOtherMedicalExpensesTotalCost(reportVO.getOtherMedicalExpensesTotalCost().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }
        //添加合计
        if(NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())){
            reportVO.setTotalDirectCost(reportVO.getTotalDirectCost().add(allocationQuery.getAmount()));
        }else{
            reportVO.setTotalIndirectCost(reportVO.getTotalIndirectCost().add(allocationQuery.getAmount()));
        }
        reportVO.setTotalCost(reportVO.getTotalCost().add(allocationQuery.getAmount()));
    }


    /**
     * 生成科室成本报表信息
     * @param reportVO
     * @param responsibility
     * @param accountType
     * @param costType
     * @param standardShareLevel
     */
    private void initDeptCostReport(BaseDeptCostReportVO reportVO,
                                    Responsibility responsibility,
                                    DictDataVo accountType,
                                    DictDataVo costType,
                                    DictDataVo standardShareLevel) {
        reportVO.setStandardShareLevel(responsibility.getStandardShareLevel());
        reportVO.setResponsibilityName(responsibility.getResponsibilityName());
        reportVO.setResponsibilityCode(responsibility.getResponsibilityCode());
        reportVO.setResponsibilitySort(responsibility.getSort());
        reportVO.setCostType(costType.getCode());
        reportVO.setStandCostType(costType.getExpandOne());
        reportVO.setAccountType(accountType.getCode());
        reportVO.setStandAccountType(accountType.getExpandOne());
        reportVO.setShareLevelSort(standardShareLevel.getSort());
    }

    /**
     * 获取所有的标准字典数据并转换所有需要的映射数据
     * @return 包含所有映射数据的DTO对象
     */
    private StandCostDictMapVO getStandCostDictMaps() {
        StandCostDictMapVO dataMaps = new StandCostDictMapVO();
        List<Responsibility> responsibilityList = responsibilityRepository.getList(UserContext.getCurrentLoginHospId());
        DictDataVo accountingTypeDict = centerService.getDict(Constant.ACCOUNTING_TYPE);
        DictDataVo costTypeDict = centerService.getDict(Constant.STANDARD_COST_CATEGORIES);
        DictDataVo standardShareLevelDict = centerService.getDict(Constant.STANDARD_SHARE_LEVEL);
        List<Accounting> allCostAccounting = accountingRepository.getAllCostAccounting();

        // 添加 null 检查
        if (responsibilityList == null) {
            responsibilityList = new ArrayList<>();
        }
        if (allCostAccounting == null) {
            allCostAccounting = new ArrayList<>();
        }

        // 创建一个映射，用于快速查找责任中心的科室类型，过滤掉 null 对象，过滤掉 responsibilityCode 为 null 的对象
        Map<String, Responsibility> responsibilityMap = responsibilityList.stream()
                .filter(Objects::nonNull)
                .filter(r -> r.getResponsibilityCode() != null)
                .collect(Collectors.toMap(Responsibility::getResponsibilityCode, o -> o));

        // 创建一个映射，用于快速查找会计科目的类型，过滤掉 null 对象，过滤掉 accountingCode 为 null 的对象
        Map<String, Accounting> accountingMap = allCostAccounting.stream()
                .filter(Objects::nonNull)
                .filter(a -> a.getAccountingCode() != null)
                .collect(Collectors.toMap(Accounting::getAccountingCode, o -> o));

        // 添加 null 检查并创建映射
        List<DictDataVo> accountingTypeDictList = (accountingTypeDict != null && accountingTypeDict.getDataVoList() != null)
                ? accountingTypeDict.getDataVoList() : new ArrayList<>();

        List<DictDataVo> costTypeDictList = (costTypeDict != null && costTypeDict.getDataVoList() != null)
                ? costTypeDict.getDataVoList() : new ArrayList<>();

        List<DictDataVo> standardShareLevelDictList = (standardShareLevelDict != null && standardShareLevelDict.getDataVoList() != null)
                ? standardShareLevelDict.getDataVoList() : new ArrayList<>();

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> accountingTypeMap = accountingTypeDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> costTypeMap = costTypeDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        // 创建一个映射，用于快速查找会计科目类型的扩展字段，过滤掉 null 对象，过滤掉 code 为 null 的对象
        Map<String, DictDataVo> standardShareLevelMap = standardShareLevelDictList.stream()
                .filter(Objects::nonNull)
                .filter(d -> d.getCode() != null)
                .collect(Collectors.toMap(DictDataVo::getCode, o -> o));

        dataMaps.setResponsibilityDict(responsibilityList);
        dataMaps.setCostAccountingDict(allCostAccounting);
        dataMaps.setCostTypeDict(costTypeDictList);
        dataMaps.setAccountingTypeDict(accountingTypeDictList);
        dataMaps.setStandardShareLevelDict(standardShareLevelDictList);
        dataMaps.setAccountingMap(accountingMap);
        dataMaps.setCostTypeMap(costTypeMap);
        dataMaps.setResponsibilityMap(responsibilityMap);
        dataMaps.setStandardShareLevelMap(standardShareLevelMap);
        dataMaps.setAccountingTypeMap(accountingTypeMap);
        return dataMaps;
    }


    /**
     *  转换为DeptDirectMedicalCostVO（一个责任中心只一条记录）
     * @param allocationQuery
     * @param standCostDictMaps
     * @return
     */
    public void addDeptDirectMedicalCostVO(Map<String ,DeptDirectMedicalCostVO> deptDirectMedicalCostMap,
                                           AllocationQuery allocationQuery,
                                           StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }
        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }
        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        //只处理医疗成本
        if(!NumberConstant.ONE_S.equals(accountType.getExpandOne()) ){
            return;
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(account.getCostType());
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());
        DeptDirectMedicalCostVO deptDirectMedicalCostVO= new DeptDirectMedicalCostVO();
        if(deptDirectMedicalCostMap.containsKey(allocationQuery.getResponsibilityCode())){
            deptDirectMedicalCostVO=deptDirectMedicalCostMap.get(allocationQuery.getResponsibilityCode());
        }else{
            initDeptCostReport(deptDirectMedicalCostVO, responsibility,accountType, costType,standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(deptDirectMedicalCostVO);
        }
        // 根据费用类型累加到对应字段
        switch (accountType.getExpandOne()) {
            case "1":
                deptDirectMedicalCostVO.setPersonnelExpense(deptDirectMedicalCostVO.getPersonnelExpense().add((allocationQuery.getAmount())));
                break;
            case "2":
                deptDirectMedicalCostVO.setHealthMaterialFee(deptDirectMedicalCostVO.getHealthMaterialFee().add((allocationQuery.getAmount())));
                break;
            case "3":
                deptDirectMedicalCostVO.setDrugFee(deptDirectMedicalCostVO.getDrugFee().add((allocationQuery.getAmount())));
                break;
            case "4":
                deptDirectMedicalCostVO.setFixedAssetDepreciation(deptDirectMedicalCostVO.getFixedAssetDepreciation().add((allocationQuery.getAmount())));
                break;
            case "5":
                deptDirectMedicalCostVO.setIntangibleAssetAmortization(deptDirectMedicalCostVO.getIntangibleAssetAmortization().add((allocationQuery.getAmount())));
                break;
            case "6":
                deptDirectMedicalCostVO.setMedicalRiskFundExtraction(deptDirectMedicalCostVO.getMedicalRiskFundExtraction().add((allocationQuery.getAmount())));
                break;
            case "7":
                deptDirectMedicalCostVO.setOtherMedicalExpenses(deptDirectMedicalCostVO.getOtherMedicalExpenses().add((allocationQuery.getAmount())));
                break;
            default:
                break;
        }
        // 更新总计
        deptDirectMedicalCostVO.setTotal(deptDirectMedicalCostVO.getTotal().add(allocationQuery.getAmount()));
    }



    /**
     * 转换为DeptDirectAllCostVO（一个责任中心只一条记录）
     * @param reportMap
     * @param allocationQuery
     * @param standCostDictMaps
     */
    private void addDeptDirectAllCostVO(Map<String, DeptFullDirectCostVO> reportMap, AllocationQuery allocationQuery, StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return; // 添加 null 检查
        }
        
        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return; // 添加 null 检查
        }
        
        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return; // 添加 null 检查
        }
        DictDataVo costType = standCostDictMaps.getCostTypeMap().get(account.getCostType());
        DictDataVo standardShareLevel = standCostDictMaps.getStandardShareLevelMap().get(responsibility.getStandardShareLevel());

        DeptFullDirectCostVO reportVO = new DeptFullDirectCostVO();
        if (reportMap.containsKey(allocationQuery.getResponsibilityCode())) {
            reportVO = reportMap.get(allocationQuery.getResponsibilityCode());
        } else {
            initDeptCostReport(reportVO, responsibility,accountType, costType,standardShareLevel);
            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(reportVO);
        }

        // 根据费用类型累加到对应字段
        switch (costType.getValue()) {
            case "1":
                reportVO.setMedicalCostTotal(reportVO.getMedicalCostTotal().add(allocationQuery.getAmount()));
                break;
            case "2":
                reportVO.setFinancialProjectFunds(reportVO.getFinancialProjectFunds().add(allocationQuery.getAmount()));
                break;
            case "3":
                reportVO.setNonPeerFinancialFunds(reportVO.getNonPeerFinancialFunds().add(allocationQuery.getAmount()));
                break;
            case "4":
                reportVO.setEducationalExpenses(reportVO.getEducationalExpenses().add(allocationQuery.getAmount()));
                break;
            case "5":
                reportVO.setAssetDisposalFees(reportVO.getAssetDisposalFees().add(allocationQuery.getAmount()));
                break;
            default:
                break;
        }
        //不是医院全成本的都是医疗全成本
        if(!NumberConstant.THREE_S.equals(costType.getExpandOne())){
            // 医疗全成本合计
            reportVO.setMedicalTotalCost(reportVO.getMedicalTotalCost().add(allocationQuery.getAmount()));
        }
        // 医院全成本合计
        reportVO.setHospitalTotalCost(reportVO.getHospitalTotalCost().add(allocationQuery.getAmount()));
    }
    

    /**
     * 合并两个科室成本
     * @param source 源对象
     * @param target 目标对象
     */
    public <T> void addBigDecimalFields(T source, T target) {
        if (source == null || target == null) {
            return;
        }
        Class<?> clazz = target.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.getType().equals(BigDecimal.class)) {
                field.setAccessible(true);
                try {
                    BigDecimal sourceValue = (BigDecimal) field.get(source);
                    BigDecimal targetValue = (BigDecimal) field.get(target);

                    BigDecimal result = (targetValue == null ? BigDecimal.ZERO : targetValue)
                            .add(sourceValue == null ? BigDecimal.ZERO : sourceValue);

                    field.set(target, result);
                } catch (IllegalAccessException e) {
                    log.error("合并科室成本时发生错误", e);
                }
            }
        }
    }


    /**
     * 通用创建小计对象方法
     * @param source 源对象
     * @param totalName 小计名称
     * @param clazz 目标类类型
     * @return 小计对象
     */
    public <T> T createSubtotalVo(T source, String totalName, Class<T> clazz) {
        if (source == null) {
            return null;
        }
        T target = BeanUtil.convertObj(source, clazz);
        // 使用反射设置责任代码和名称
        try {
            clazz.getMethod("setResponsibilityCode", String.class).invoke(target, totalName);
            clazz.getMethod("setResponsibilityName", String.class).invoke(target, totalName);
        } catch (Exception e) {
            log.error("设置责任代码和名称时发生错误", e);
        }
        // 初始化所有费用字段为0
        BeanUtil.initBigDecimalFieldsToZero(target);
        return target;
    }

    // 新增方法，用于设置科室金额
    private void putDepartmentAmount(ClinicalDeptFullCostVO vo, String deptName, BigDecimal amount) {
        try {
            Field field = vo.getClass().getDeclaredField(deptName);
            field.setAccessible(true);
            field.set(vo, amount);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("设置科室金额时发生错误", e);
        }
    }

    /**
     * 获取诊次床日分摊参数代码
     * @return
     */
    public String[] getVisitsBedDaysParamCode(){
        String parameterValue = centerService.getParameterValue(ParameterConstant.VISITS_BED_DAYS_PARAM_CODE);
        if(StringUtils.isEmpty(parameterValue)||Constant.EMPTY_STR.equals(parameterValue)){
            throw new CostException("请配置诊次床日分摊参数代码");
        }
        String[] split = parameterValue.split(SplitConstant.SEPARATOR_VERTICALLINE);
        if(!NumberConstant.TWO.equals(split.length)){
            throw new CostException("配置的诊次床日分摊参数代码不正确");
        }
        return split;
    }

    /**
     * 获取医院科室成本分摊汇总表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalDeptCostAllocationVO> getHospitalDeptCostAllocation(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAllByDate(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }

        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();

        // 处理 allocationQueryList 数据
        Map<String, HospitalDeptCostAllocationVO> deptCostAllocationMap = new HashMap<>();

        // 转换为HospitalDeptCostAllocationVO（一个责任中心只一条记录）
        for (AllocationQuery allocationQuery : allocationQueryList) {
            addHospitalDeptCostAllocationVO(deptCostAllocationMap, allocationQuery, standCostDictMaps);
        }

        // 转成List便于处理
        List<HospitalDeptCostAllocationVO> reportList = new ArrayList<>(deptCostAllocationMap.values());
        //创建总计
        HospitalDeptCostAllocationVO grandTotal = createSubtotalVo(reportList.get(NumberConstant.ZERO), "总计", HospitalDeptCostAllocationVO.class);
        // 按responsibilitySort正序排序
        reportList.sort(Comparator.comparing(HospitalDeptCostAllocationVO::getResponsibilitySort,
                Comparator.nullsLast(Comparator.naturalOrder())));

        // 按标准分级分组
        Map<String, List<HospitalDeptCostAllocationVO>> shareLevelGroup = reportList.stream()
                .collect(Collectors.groupingBy(HospitalDeptCostAllocationVO::getStandardShareLevel));

        // 科室标准分级按顺序号倒序排序
        List<DictDataVo> standardShareLevelList = standCostDictMaps.getStandardShareLevelDict();
        standardShareLevelList.sort(Comparator.comparing(DictDataVo::getSort, Comparator.nullsLast(Comparator.reverseOrder())));

        // 创建各层级小计并按正确顺序插入
        List<HospitalDeptCostAllocationVO> result = new ArrayList<>();
        for (DictDataVo shareLevel : standardShareLevelList) {
            List<HospitalDeptCostAllocationVO> deptCostAllocationVOS = shareLevelGroup.get(shareLevel.getCode());
            if (CollectionUtils.isEmpty(deptCostAllocationVOS)) {
                continue;
            }
            // 添加该分类下的所有记录
            result.addAll(deptCostAllocationVOS);
            // 创建小计对象
            HospitalDeptCostAllocationVO subtotalVo = createSubtotalVo(deptCostAllocationVOS.get(NumberConstant.ZERO), String.format("%s小计", shareLevel.getName()), HospitalDeptCostAllocationVO.class);
            //将科室的金额加到小计对象中
            deptCostAllocationVOS.forEach(item -> addBigDecimalFields(item, subtotalVo));
            // 小计的金额加到总计
            addBigDecimalFields(subtotalVo, grandTotal);
            // 添加小计行
            result.add(subtotalVo);
        }
        // 总计加到列表最后面
        result.add(grandTotal);
        return result;
    }

    /**
     * 获取医院诊次成本构成表数据
     * @param computeDate 核算年月
     * @return 报表数据
     */
    @Override
    public List<HospitalVisitCostCompositionVO> getHospitalVisitCostComposition(String computeDate) {
        DateTime parse = DateUtil.parse(computeDate);
        int year = DateUtil.year(parse);
        int month = DateUtil.month(parse) + 1;

        // 获取科室成本
        List<AllocationQuery> allocationQueryList = allocationQueryService.getAcountAccounts(UserContext.getCurrentLoginHospId(), year, month);
        if (CollectionUtils.isEmpty(allocationQueryList)) {
            throw new CostException("医院未分摊本月数据");
        }
        //获取分摊参数
        List<ShareParamValue> shareParamValueList = shareParamValueRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(shareParamValueList)) {
            throw new CostException("未获取医院本月分摊参数数据");
        }
        // 获取所有的标准字典数据
        StandCostDictMapVO standCostDictMaps = getStandCostDictMaps();
        //获取成本会计科目字典
        List<DictDataVo> accountingTypeDict = standCostDictMaps.getAccountingTypeDict();
        List<DictDataVo> costAccountingTypeDict = accountingTypeDict.stream().filter(dictDataVo -> NumberConstant.TWO_S.equals(dictDataVo.getValue())).collect(Collectors.toList());
        // 初始化成本项目映射
        Map<String, HospitalVisitCostCompositionVO> costItemMap =createHospitalVisitCostCompositionVO(costAccountingTypeDict);
        // 处理分配查询数据
        for (AllocationQuery allocationQuery : allocationQueryList) {
            String accountingCode = allocationQuery.getAccountingCode();
            Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
            if (account == null) {
                continue;
            }
            DictDataVo costType = standCostDictMaps.getCostTypeMap().get(account.getCostType());
            HospitalVisitCostCompositionVO vo = costItemMap.get(account.getType());
            // 医疗成本
            if ("1".equals(costType.getExpandOne())) {
                vo.setMedicalCost(vo.getMedicalCost().add(allocationQuery.getAmount()));
            }
            // 医疗全成本
            if (!"3".equals(costType.getExpandOne())) {
                vo.setMedicalFullCost(vo.getMedicalFullCost().add(allocationQuery.getAmount()));
            }
            // 医院全成本
            vo.setHospitalFullCost(vo.getHospitalFullCost().add(allocationQuery.getAmount()));
        }
        //获取诊次床日分摊参数代码
        String[] visitsBedDaysParamCode = getVisitsBedDaysParamCode();

        // 诊次分摊参数值
        BigDecimal visitParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ZERO]);
//        // 床日分摊参数值
//        BigDecimal bedDaysParamValue = getParamValue(shareParamValueList, visitsBedDaysParamCode[NumberConstant.ONE]);

        //处理总计和药品小计
        HospitalVisitCostCompositionVO totalVo = new HospitalVisitCostCompositionVO();
        totalVo.setCostItem("总计");
        HospitalVisitCostCompositionVO drugTotalVo = new HospitalVisitCostCompositionVO();
        totalVo.setCostItem("药品费");
        // 转成List便于处理
        List<HospitalVisitCostCompositionVO> reportList = costItemMap.values().stream().collect(Collectors.toList());
        for (HospitalVisitCostCompositionVO item : reportList) {
            //计算每诊次的医疗全成本
            item.setHospitalFullCost(getPercent(visitParamValue,totalVo.getHospitalFullCost()));
            //计算每诊次的医疗成本
            item.setMedicalCost(getPercent(visitParamValue,totalVo.getMedicalCost()));
            //计算每诊次的医院全成本
            item.setHospitalFullCost(getPercent(visitParamValue,totalVo.getMedicalFullCost()));
            // 将金额加到总计对象中
            addBigDecimalFields(item, totalVo);
            /// 将金额加到药品对象中
            if(NumberConstant.THREE_S.equals(item.getCostType())){
                addBigDecimalFields(item, drugTotalVo);
            }
        }
        //添加到列表的指定位置
        reportList.add(NumberConstant.TWO,drugTotalVo);
        reportList.add(NumberConstant.ZERO,totalVo);
        return reportList;
    }

    /**
     * 添加医院科室成本分摊数据
     * @param deptCostAllocationMap 科室成本分摊Map
     * @param allocationQuery 分摊查询对象
     * @param standCostDictMaps 标准字典数据
     */
    private void addHospitalDeptCostAllocationVO(Map<String, HospitalDeptCostAllocationVO> deptCostAllocationMap,
                                                 AllocationQuery allocationQuery,
                                                 StandCostDictMapVO standCostDictMaps) {
        String responsibilityCode = allocationQuery.getTargetResponsibilityCode();
        String sourceResponsibilityCode = allocationQuery.getResponsibilityCode();
        Responsibility responsibility = standCostDictMaps.getResponsibilityMap().get(responsibilityCode);
        if (responsibility == null) {
            return;
        }

        Responsibility sourceResponsibility = standCostDictMaps.getResponsibilityMap().get(sourceResponsibilityCode);
        if (sourceResponsibility == null) {
            return;
        }

        String accountingCode = allocationQuery.getAccountingCode();
        Accounting account = standCostDictMaps.getAccountingMap().get(accountingCode);
        if (account == null) {
            return;
        }

        DictDataVo accountType = standCostDictMaps.getAccountingTypeMap().get(account.getType());
        if (accountType == null) {
            return;
        }

        HospitalDeptCostAllocationVO costAllocationVO = new HospitalDeptCostAllocationVO();
        if (deptCostAllocationMap.containsKey(responsibilityCode)) {
            costAllocationVO = deptCostAllocationMap.get(responsibilityCode);
        } else {
            // 初始化VO对象
            costAllocationVO.setResponsibilityName(responsibility.getResponsibilityName());
            costAllocationVO.setResponsibilityCode(responsibility.getResponsibilityCode());
            costAllocationVO.setResponsibilitySort(responsibility.getSort());
            costAllocationVO.setStandardShareLevel(responsibility.getStandardShareLevel());

            // 初始化所有费用字段为0
            BeanUtil.initBigDecimalFieldsToZero(costAllocationVO);
        }

        // 直接成本
        if (NumberConstant.ONE.equals(allocationQuery.getOriginType().intValue())) {
            costAllocationVO.setDirectCost(
                    (costAllocationVO.getDirectCost() == null ? BigDecimal.ZERO : costAllocationVO.getDirectCost())
                            .add(allocationQuery.getAmount()));
        }else{
            switch (sourceResponsibility.getStandardShareLevel())
            {
                case "1":
                    // 行政后勤类科室成本
                    costAllocationVO.setAllocatedAdminCost(
                            (costAllocationVO.getAllocatedAdminCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedAdminCost())
                                    .add(allocationQuery.getAmount()));
                case "2":
                    // 辅助支持类科室成本
                    costAllocationVO.setAllocatedSupportCost(
                            (costAllocationVO.getAllocatedSupportCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedSupportCost())
                                    .add(allocationQuery.getAmount()));
                case "3":
                    // 技术类科室成本
                    costAllocationVO.setAllocatedTechCost(
                            (costAllocationVO.getAllocatedTechCost() == null ? BigDecimal.ZERO : costAllocationVO.getAllocatedTechCost())
                                    .add(allocationQuery.getAmount()));
                break;
            }
            //小计
            costAllocationVO.setSubtotal(
                    (costAllocationVO.getSubtotal() == null ? BigDecimal.ZERO : costAllocationVO.getSubtotal())
                            .add(allocationQuery.getAmount()));
        }
        // 医疗类科室成本
        costAllocationVO.setMedicalCost(
                (costAllocationVO.getMedicalCost() == null ? BigDecimal.ZERO : costAllocationVO.getMedicalCost())
                        .add(allocationQuery.getAmount()));
        deptCostAllocationMap.put(responsibilityCode, costAllocationVO);
    }


    /**
     * 获取指定分摊参数的数值
     * @param shareParamValues
     * @param paramCode
     * @return
     */
    public BigDecimal getParamValue(List<ShareParamValue> shareParamValues, String paramCode){
        BigDecimal sum = shareParamValues.stream()
                .filter(shareParamValue -> shareParamValue.getShareParamCode().equals(paramCode))
                .map(ShareParamValue::getValueNum)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return sum;
    }

    /**
     * 创建医院诊次成本构成表数据
     * @param costAccountingTypeDict
     * @return
     */
    public Map<String, HospitalVisitCostCompositionVO> createHospitalVisitCostCompositionVO(List<DictDataVo> costAccountingTypeDict) {
        // 初始化成本项目映射
        Map<String, HospitalVisitCostCompositionVO> costItemMap = new HashMap<>();
        for (DictDataVo dictDataVo : costAccountingTypeDict) {
            HospitalVisitCostCompositionVO vo = new HospitalVisitCostCompositionVO();
            vo.setCostCode(dictDataVo.getCode());
            vo.setCostItem(dictDataVo.getName());
            vo.setCostType(dictDataVo.getExpandOne());
            vo.setMedicalCost(BigDecimal.ZERO);
            vo.setMedicalFullCost(BigDecimal.ZERO);
            vo.setHospitalFullCost(BigDecimal.ZERO);
            costItemMap.put(dictDataVo.getCode(), vo);
        }
        return costItemMap;
    }


}