package com.kcim.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.enums.ReportItemTypeEnum;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.*;
import com.kcim.dao.model.dto.ComputeClinicalPathwayCostPageDto;
import com.kcim.dao.model.dto.ComputeItemGroupByVisitNoDto;
import com.kcim.dao.model.dto.ComputePatientCostGroupByDepartmentDto;
import com.kcim.dao.repository.*;
import com.kcim.service.ComputeClinicalPathwayCostService;
import com.kcim.service.ComputeItemCostService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description: 临床路径成本计算接口实现类
 * @author: Wang.YS
 * @create: 2023-10-31 17:12
 **/
@Service("ComputeClinicalPathwayCostService")
@Slf4j
@AllArgsConstructor
public class ComputeClinicalPathwayCostServiceImpl implements ComputeClinicalPathwayCostService {
    /**
     * 临床路径主表
     */
    ComputeClinicalPathwayCostRepository repository;
    /**
     * 临床路径明细表
     */
    ComputeClinicalPathwayCostDetailRepository detailRepository;

    /**
     * 患者信息导入
     */
    ImportPatientInfoRepository importPatientInfoRepository;
    /**
     * 病人成本计算
     */
    ComputePatientCostRepository computePatientCostRepository;
    ComputeItemCostRepository computeItemCostRepository;
    ComputeItemCostService computeItemCostService;
    /**
     * 临床路径分而查询
     *
     * @param current      当前页
     * @param pageSize     页容量
     * @param computeDate  核算年月
     * @param clinicalName 路径名称
     * @return 列表
     */
    @Override
    public Object clinicalPathwayCostCalculateList(Integer current, Integer pageSize, String computeDate, String clinicalName) {
        Page<ComputeClinicalPathwayCostPageDto> page = repository.getByPage(current, pageSize, computeDate, clinicalName);
        if(CollectionUtils.isEmpty(page.getRecords())){
            return new PageUtils(new ArrayList<>(), NumberConstant.ZERO,pageSize,current);
        }
        return new PageUtils(page.getRecords(), Math.toIntExact(page.getTotal()),pageSize,current);    }

    /**
     * 临床路径计算
     *
     * @param computeDate 核算年月
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void clinicalPathwayCostCalculate(String computeDate) {
        List<ImportPatientInfo> patientInfos = importPatientInfoRepository.getByComputeDate(computeDate);
        if(CollectionUtils.isEmpty(patientInfos)){
            log.error("未导入当前核算年月【"+computeDate+"】患者信息，计算中止");
            throw new CostException("未导入当前核算年月【"+computeDate+"】患者信息，当前计算中止");
        }
//获取计算过的项目信息
        List<ComputePatientCostGroupByDepartmentDto> patientCostDepartmentGroup = computePatientCostRepository.getPatientCostDepartmentGroup(computeDate);
        if(CollectionUtils.isEmpty(patientCostDepartmentGroup)){
            throw new CostException("当前核算年月【"+computeDate+"】未计算病人成本信息，请先计算病人成本信息，当前计算中止");
        }

        List<ComputeItemGroupByVisitNoDto> byComputeDateGroupByVisitNo = computeItemCostRepository.getByComputeDateGroupByVisitNo(computeDate);
//            List<ComputePatientCostGroupByDepartmentDto> patientCostDepartmentGroup = computePatientCostRepository.getPatientCostDepartmentGroup(computeDate);
        if(CollectionUtils.isEmpty(byComputeDateGroupByVisitNo)){
            throw new CostException("当前核算年月【"+computeDate+"】未计算收费项目成本计算，请先计算收费项目成本，当前计算中止");
        }
        Map<String, ComputeItemGroupByVisitNoDto> computeItemGroup = byComputeDateGroupByVisitNo.stream().collect(Collectors.toMap(ComputeItemGroupByVisitNoDto::getVisitNo, dto -> dto, (a, b) -> b));

//        Map<String, ComputePatientCostGroupByDepartmentDto> computeItemGroup = patientCostDepartmentGroup.stream().collect(Collectors.toMap(ComputePatientCostGroupByDepartmentDto::getDepartmentCode, dto -> dto, (a, b) -> b));

        //过滤掉分组为空的数据
        List<ImportPatientInfo> patientInfoList = patientInfos.stream().filter(patientInfo -> !StringUtils.isEmpty(patientInfo.getClinicalPathwayCode())).collect(Collectors.toList());
        //按分组和科室进行分组
        Map<String, List<ImportPatientInfo>> clinical = patientInfoList.stream().collect(Collectors.groupingBy(ImportPatientInfo::getClinicalPathwayCode));

        ComputeClinicalPathwayCost computeClinicalPathwayCost = new ComputeClinicalPathwayCost();
        computeClinicalPathwayCost.setComputeDate(computeDate);
        computeClinicalPathwayCost.setHospId(UserContext.getHospId());
        computeClinicalPathwayCost.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        computeClinicalPathwayCost.setCreateTime(new Date());
        ComputeClinicalPathwayCostDetail clinicalPathwayCostDetail = new ComputeClinicalPathwayCostDetail();
        clinicalPathwayCostDetail.setHospId(UserContext.getHospId());
        clinicalPathwayCostDetail.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        clinicalPathwayCostDetail.setCreateTime(new Date());
        final int[] index = {0};
        List<ComputeClinicalPathwayCost> saveClinicalCost = new ArrayList<>();
        List<ComputeClinicalPathwayCostDetail> details = new ArrayList<>();
        clinical.forEach((k,v)->{
            String clinicalMame = v.get(0).getGroupName();
            Map<String, List<ImportPatientInfo>> departmentGroup = v.stream().collect(Collectors.groupingBy(ImportPatientInfo::getDepartmentCode));
            departmentGroup.forEach((k1,v1)->{
                ComputeClinicalPathwayCost groupCost = BeanUtil.convertObj(computeClinicalPathwayCost, ComputeClinicalPathwayCost.class);
                groupCost.setCode(k);
                groupCost.setName(clinicalMame);
                groupCost.setDepartmentCode(k1);
                groupCost.setDepartmentName(v1.get(0).getDepartmentName());
                groupCost.setPatientNum(v1.size());
                groupCost.setIndex(index[0]);
                List<ComputeItemGroupByVisitNoDto> dtoList = v1.stream().map(info -> computeItemGroup.get(info.getVisitNo())).collect(Collectors.toList());
                List<ComputeClinicalPathwayCostDetail> detail = getDetail(index[0], clinicalPathwayCostDetail, dtoList);
                saveClinicalCost.add(groupCost);
                details.addAll(detail);
                index[0]++;
            });

        });
//        for (String clinicalCode : clinical.keySet()) {
//            List<ImportPatientInfo> clinicalGroup = clinical.get(clinicalCode);
//            String clinicalMame = clinicalGroup.get(0).getGroupName();
//            Map<String, List<ImportPatientInfo>> departmentGroup = clinicalGroup.stream().collect(Collectors.groupingBy(ImportPatientInfo::getDepartmentCode));
//            for (String departmentCode : departmentGroup.keySet()) {
//                ComputeClinicalPathwayCost groupCost = BeanUtil.convertObj(computeClinicalPathwayCost, ComputeClinicalPathwayCost.class);
//                groupCost.setCode(clinicalCode);
//                groupCost.setName(clinicalMame);
//                groupCost.setDepartmentCode(departmentCode);
//                List<ImportPatientInfo> infos = departmentGroup.get(departmentCode);
//                groupCost.setDepartmentName(infos.get(0).getDepartmentName());
//                groupCost.setPatientNum(infos.size());
//                groupCost.setIndex(index[0]);
//                List<ComputeItemGroupByVisitNoDto> dtoList = infos.stream().map(info -> computeItemGroup.get(info.getVisitNo())).collect(Collectors.toList());
//
////                ComputePatientCostGroupByDepartmentDto patientCost = computeItemGroup.get(departmentCode);
//                List<ComputeClinicalPathwayCostDetail> detail = getDetail(index[0], clinicalPathwayCostDetail, dtoList);
//                saveClinicalCost.add(groupCost);
//                details.addAll(detail);
//                index[0]++;
//            }
//        }

        if(!CollectionUtils.isEmpty(saveClinicalCost)){
            //作废当前核算年月已有数据
            List<Integer> integers = repository.removeByComputeDate(computeDate);
            if(!CollectionUtils.isEmpty(integers)){
                detailRepository.removeByClinicalCostId(integers);
            }
            repository.saveBatch(saveClinicalCost,100);
            if(!CollectionUtils.isEmpty(saveClinicalCost)){
                Map<Integer,Integer> indexId = saveClinicalCost.stream().collect(Collectors.toMap(ComputeClinicalPathwayCost::getIndex, ComputeClinicalPathwayCost::getId, (a, b) -> b));
                Map<Integer, List<ComputeClinicalPathwayCostDetail>> collect = details.stream().collect(Collectors.groupingBy(ComputeClinicalPathwayCostDetail::getIndex));
                List<ComputeClinicalPathwayCostDetail> saveCostDetails = new ArrayList<>();
                collect.forEach((k,v)->{
                    v.forEach(detail -> detail.setClinicalPathwayId(indexId.get(k)));
                    saveCostDetails.addAll(v);
                });
                detailRepository.saveBatch(saveCostDetails,500);
            }
        }
    }

    private List<ComputeClinicalPathwayCostDetail> getDetail(int i, ComputeClinicalPathwayCostDetail costDetail, List<ComputeItemGroupByVisitNoDto> dtoList) {
        List<String> itemTypeList = computeItemCostService.getItemTypeList();
        List<ComputeClinicalPathwayCostDetail> details = new ArrayList<>();
        for (String s : itemTypeList) {
            ComputeClinicalPathwayCostDetail detail = BeanUtil.convertObj(costDetail, ComputeClinicalPathwayCostDetail.class);
            detail.setType(s);
            detail.setIndex(i);
            if(s.equals(ReportItemTypeEnum.DRUG_INCOME.getCode())){
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getDrugIncome());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.MATERIAL_INCOME.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getMaterialIncome());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.ITEM_INCOME.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getItemIncome());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.DRUG_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getDrugCost());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.MATERIAL_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getMaterialCost());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.ITEM_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getItemCost());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.EMP_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getEmpCost());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.EQUIPMENT_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getEquipmentCost());
                }
                detail.setComputeResult(bigDecimal);
            }else if (s.equals(ReportItemTypeEnum.SPACE_COST.getCode())) {
                BigDecimal bigDecimal = new BigDecimal("0.0000");
                for (ComputeItemGroupByVisitNoDto dto : dtoList) {
                    bigDecimal = bigDecimal.add(dto.getSpaceCost());
                }
                detail.setComputeResult(bigDecimal);
            }  else {
                detail.setComputeResult(BigDecimal.ZERO);
            }
            details.add(detail);
        }
        return details;
    }

}
