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.ComputeDiseaseCostPageDto;
import com.kcim.dao.model.dto.ComputeItemGroupByVisitNoDto;
import com.kcim.dao.model.dto.ComputePatientCostGroupByDepartmentDto;
import com.kcim.dao.repository.*;
import com.kcim.service.ComputeDiseaseCostService;
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.*;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description: 病种成本计算接口实现类
 * @author: Wang.YS
 * @create: 2023-10-31 10:56
 **/
@Slf4j
@AllArgsConstructor
@Service("ComputeDiseaseCostService")
public class ComputeDiseaseCostServiceImpl implements ComputeDiseaseCostService {

    /**
     * 病种成本计算主表
     */
    ComputeDiseaseCostRepository repository;

    /**
     * 病种成本计算明细表
     */
    ComputeDiseaseCostDetailRepository detailRepository;
    /**
     * 病种字典管理
     */
    DiseaseTypeRepository diseaseTypeRepository;
    /**
     * 患者信息导入
     */
    ImportPatientInfoRepository importPatientInfoRepository;
    /**
     * 病人成本计算
     */
    ComputePatientCostRepository computePatientCostRepository;

    ComputeItemCostRepository computeItemCostRepository;

    ComputeItemCostService computeItemCostService;

    DiseaseTypeDiagMapRepository diagMapRepository;
    /**
     * 病种成本计算获取列表-分页
     *
     * @param current        当前页
     * @param pageSize       页容量
     * @param computeDate    核算年月
     * @param departmentName 科室名称
     * @param diseaseName    病种名称
     * @return 列表
     */
    @Override
    public Object diseaseCostCalculateList(Integer current, Integer pageSize, String computeDate, String departmentName, String diseaseName) {
        Page<ComputeDiseaseCostPageDto> page = repository.getByPage(current, pageSize, computeDate, departmentName, diseaseName);
        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 diseaseCostCalculate(String computeDate) {
//        try {
             /*
            1 获取所有病人信息导入数据
            2 过滤掉未对照病种为空的数据
         */
        List<ImportPatientInfo> patientInfos = importPatientInfoRepository.getByComputeDate(computeDate);
        if(CollectionUtils.isEmpty(patientInfos)){
            log.error("未导入当前核算年月【"+computeDate+"】患者信息，计算中止");
            throw new CostException("未导入当前核算年月【"+computeDate+"】患者信息，当前计算中止");
        }
        Map<String, String> diseaseNameMap = diseaseTypeRepository.getDiseaseNameMap();
        if(CollectionUtils.isEmpty(diseaseNameMap)){
            log.error("病种字典未导入/编护，计算中止");
            throw new CostException("病种字典未导入/编护，计算中止");
        }
        //获取计算过的项目信息
        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, String> diagDiseaseMap = diagMapRepository.getDiagDiseaseMap();
            //病种与诊断对照
        if(!CollectionUtils.isEmpty(diagDiseaseMap)){
            for (ImportPatientInfo patientInfo : patientInfos) {
                if(!StringUtils.isEmpty(patientInfo.getPrimaryDiagCode())){
                    String diseaseType = diagDiseaseMap.get(patientInfo.getPrimaryDiagCode());
                    if(!StringUtils.isEmpty(diseaseType)){
                        patientInfo.setDiseaseTypeCode(diseaseType);
                    }
                }
            }
        }
        //过滤掉病种分类为空的数据
        List<ImportPatientInfo> patientInfoList = patientInfos.stream().filter(patientInfo -> !StringUtils.isEmpty(patientInfo.getDiseaseTypeCode())).collect(Collectors.toList());
        //按病种分类和科室进行分组
        Map<String, List<ImportPatientInfo>> diseaseGroup = patientInfoList.stream().collect(Collectors.groupingBy(ImportPatientInfo::getDiseaseTypeCode));

        ComputeDiseaseCost computeDiseaseCost = new ComputeDiseaseCost();
        computeDiseaseCost.setComputeDate(computeDate);
        computeDiseaseCost.setHospId(UserContext.getHospId());
        computeDiseaseCost.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        computeDiseaseCost.setCreateTime(new Date());
        ComputeDiseaseCostDetail diseaseCostDetail = new ComputeDiseaseCostDetail();
        diseaseCostDetail.setHospId(UserContext.getHospId());
        diseaseCostDetail.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        diseaseCostDetail.setCreateTime(new Date());
        int index = 0;
        List<ComputeDiseaseCost> savePatientCost = new ArrayList<>();
        List<ComputeDiseaseCostDetail> details = new ArrayList<>();
        for (String diseaseTypeCode : diseaseGroup.keySet()) {
            List<ImportPatientInfo> groups = diseaseGroup.get(diseaseTypeCode);
            Map<String, List<ImportPatientInfo>> departmentGroup = groups.stream().collect(Collectors.groupingBy(ImportPatientInfo::getDepartmentCode));
            for (String departmentCode : departmentGroup.keySet()) {
                ComputeDiseaseCost diseaseCost = BeanUtil.convertObj(computeDiseaseCost, ComputeDiseaseCost.class);
                diseaseCost.setCode(diseaseTypeCode);
                diseaseCost.setName(diseaseNameMap.get(diseaseTypeCode));
                diseaseCost.setDepartmentCode(departmentCode);
                List<ImportPatientInfo> infos = departmentGroup.get(departmentCode);
                diseaseCost.setDepartmentName(infos.get(0).getDepartmentName());
                diseaseCost.setPatientNum(infos.size());
                diseaseCost.setIndex(index);
                List<ComputeItemGroupByVisitNoDto> dtoList = infos.stream().map(info -> computeItemGroup.get(info.getVisitNo())).collect(Collectors.toList());
//                ComputePatientCostGroupByDepartmentDto patientCost = computeItemGroup.get(departmentCode);
                dtoList.removeAll(Collections.singleton(null));
                List<ComputeDiseaseCostDetail> detail = !CollectionUtils.isEmpty(dtoList) ? getDetail(index, diseaseCostDetail, dtoList) : getDefaultDetail(index, diseaseCostDetail);
                savePatientCost.add(diseaseCost);
                details.addAll(detail);
                index++;
            }
        }

        if(!CollectionUtils.isEmpty(savePatientCost)){
            //作废当前核算年月已有数据
            List<Integer> integers = repository.removeByComputeDate(computeDate);
            if(!CollectionUtils.isEmpty(integers)){
                detailRepository.removeByDiseaseCostId(integers);
            }
            repository.saveBatch(savePatientCost,100);
            if(!CollectionUtils.isEmpty(savePatientCost)){
                Map<Integer,Integer> indexId = savePatientCost.stream().collect(Collectors.toMap(ComputeDiseaseCost::getIndex, ComputeDiseaseCost::getId, (a, b) -> b));
                Map<Integer, List<ComputeDiseaseCostDetail>> collect = details.stream().collect(Collectors.groupingBy(ComputeDiseaseCostDetail::getIndex));
                List<ComputeDiseaseCostDetail> saveCostDetails = new ArrayList<>();
                collect.keySet().forEach(integer -> {
                    Integer costId = indexId.get(integer);
                    List<ComputeDiseaseCostDetail> detailList = collect.get(integer);
                    detailList.forEach(detail -> detail.setDiseaseCostId(costId));
                    saveCostDetails.addAll(detailList);
                });
                detailRepository.saveBatch(saveCostDetails,500);
            }
        }
//        }catch (Exception e){
//            log.error(e.getMessage());
//            throw new CostException(e.getMessage());
//        }




    }

    private List<ComputeDiseaseCostDetail> getDetail(int i, ComputeDiseaseCostDetail costDetail, List<ComputeItemGroupByVisitNoDto> dtoList) {
        List<String> itemTypeList = computeItemCostService.getItemTypeList();
        List<ComputeDiseaseCostDetail> details = new ArrayList<>();
        for (String s : itemTypeList) {
            ComputeDiseaseCostDetail detail = BeanUtil.convertObj(costDetail, ComputeDiseaseCostDetail.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;
    }
    private List<ComputeDiseaseCostDetail> getDefaultDetail(int i, ComputeDiseaseCostDetail costDetail) {
        List<String> itemTypeList = computeItemCostService.getItemTypeList();
        List<ComputeDiseaseCostDetail> details = new ArrayList<>();
        for (String s : itemTypeList) {
            ComputeDiseaseCostDetail detail = BeanUtil.convertObj(costDetail, ComputeDiseaseCostDetail.class);
            detail.setType(s);
            detail.setIndex(i);
            detail.setComputeResult(BigDecimal.ZERO);
            details.add(detail);
        }
        return details;
    }


}
