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.ComputeGroupCostPageDto;
import com.kcim.dao.model.dto.ComputeItemGroupByVisitNoDto;
import com.kcim.dao.model.dto.ComputePatientCostGroupByDepartmentDto;
import com.kcim.dao.repository.*;
import com.kcim.service.ComputeGroupCostService;
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: DRG/DIP分组成本计算接口实现类
 * @author: Wang.YS
 * @create: 2023-10-31 16:15
 **/
@Service("ComputeGroupCostService")
@Slf4j
@AllArgsConstructor
public class ComputeGroupCostServiceImpl implements ComputeGroupCostService {
    /**
     * DRG/DIP分组成本主表
     */
    ComputeGroupCostRepository repository;
    /**
     * DRG/DIP分组成本明细表
     */
    ComputeGroupCostDetailRepository detailRepository;

    /**
     * 患者信息导入
     */
    ImportPatientInfoRepository importPatientInfoRepository;
    /**
     * 病人成本计算
     */
    ComputePatientCostRepository computePatientCostRepository;
    ComputeItemCostRepository computeItemCostRepository;
    ComputeItemCostService computeItemCostService;

    /**
     * DRG/DIP分组成本分页查询
     *
     * @param current        当前页
     * @param pageSize       页容量
     * @param computeDate    核算年月
     * @param departmentName 科室名称
     * @param groupName      分组名称
     * @return 分页列表
     */
    @Override
    public Object groupCostCalculateList(Integer current, Integer pageSize, String computeDate, String departmentName, String groupName) {
        Page<ComputeGroupCostPageDto> page = repository.getByPage(current, pageSize, computeDate, departmentName, groupName);
        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);

    }

    /**
     * DRG/DIP分组成本计算
     *
     * @param computeDate 核算年月
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void groupCostCalculate(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);
        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.getGroupCode())).collect(Collectors.toList());
        //按分组和科室进行分组
        Map<String, List<ImportPatientInfo>> group = patientInfoList.stream().collect(Collectors.groupingBy(ImportPatientInfo::getGroupCode));

        ComputeGroupCost computeGroupCost = new ComputeGroupCost();
        computeGroupCost.setComputeDate(computeDate);
        computeGroupCost.setHospId(UserContext.getHospId());
        computeGroupCost.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        computeGroupCost.setCreateTime(new Date());
        ComputeGroupCostDetail groupCostDetail = new ComputeGroupCostDetail();
        groupCostDetail.setHospId(UserContext.getHospId());
        groupCostDetail.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        groupCostDetail.setCreateTime(new Date());
        int index = 0;
        List<ComputeGroupCost> saveGroupCost = new ArrayList<>();
        List<ComputeGroupCostDetail> details = new ArrayList<>();
        for (String groupCode : group.keySet()) {
            List<ImportPatientInfo> groups = group.get(groupCode);
            String groupMame = groups.get(0).getGroupName();
            Map<String, List<ImportPatientInfo>> departmentGroup = groups.stream().collect(Collectors.groupingBy(ImportPatientInfo::getDepartmentCode));
            for (String departmentCode : departmentGroup.keySet()) {
                ComputeGroupCost groupCost = BeanUtil.convertObj(computeGroupCost, ComputeGroupCost.class);
                groupCost.setCode(groupCode);
                groupCost.setName(groupMame);
                groupCost.setDepartmentCode(departmentCode);
                List<ImportPatientInfo> infos = departmentGroup.get(departmentCode);
                groupCost.setDepartmentName(infos.get(0).getDepartmentName());
                groupCost.setPatientNum(infos.size());
                groupCost.setIndex(index);
                List<ComputeItemGroupByVisitNoDto> dtoList = infos.stream().map(info -> computeItemGroup.get(info.getVisitNo())).collect(Collectors.toList());
//                ComputePatientCostGroupByDepartmentDto patientCost = computeItemGroup.get(departmentCode);
//                List<ComputeDiseaseCostDetail> detail = getDetail(index, diseaseCostDetail, dtoList);
//                ComputePatientCostGroupByDepartmentDto patientCost = computeItemGroup.get(departmentCode);
                List<ComputeGroupCostDetail> detail = getDetail(index, groupCostDetail, dtoList);
                saveGroupCost.add(groupCost);
                details.addAll(detail);
                index++;
            }
        }

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


    private List<ComputeGroupCostDetail> getDetail(int i, ComputeGroupCostDetail costDetail, List<ComputeItemGroupByVisitNoDto> dtoList) {
        List<String> itemTypeList = computeItemCostService.getItemTypeList();
        List<ComputeGroupCostDetail> details = new ArrayList<>();
        for (String s : itemTypeList) {
            ComputeGroupCostDetail detail = BeanUtil.convertObj(costDetail, ComputeGroupCostDetail.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;
    }

}
