package thyyxxk.webserver.service.medicalinsurance.costcontrol;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.medicalinsurance.costcontrol.YbClnTimesAvgDao;
import thyyxxk.webserver.dao.his.medicalinsurance.costcontrol.YbUtilDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.datamodify.ZyDetailCharge;
import thyyxxk.webserver.entity.medicalinsurance.costcontrol.YbClnAvgParam;
import thyyxxk.webserver.entity.medicalinsurance.costcontrol.YbSetlInfo;
import thyyxxk.webserver.entity.medicalinsurance.costcontrol.YbkfShareDto;
import thyyxxk.webserver.utils.DecimalUtil;
import thyyxxk.webserver.utils.ResultVoUtil;

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

/**
 * @Description: 长浏宁次均控费
 * @Author: hsh
 * @CreateTime: 2022-10-26  10:47
 * @Version: 1.0
 */
@Service
@Log4j2
public class YbClnTimesAvgService {

    private final YbClnTimesAvgDao dao;

    private final YbUtilDao utilDao;

    @Autowired
    public YbClnTimesAvgService(YbClnTimesAvgDao dao, YbUtilDao utilDao) {
        this.dao = dao;
        this.utilDao = utilDao;
    }

    public ResultVo<Map<String, Object>> selectClnTimesAvg(YbkfShareDto dto) {
        String beginTime = dto.getStartTime();
        String endTime = dto.getEndTime();
        String insurName = dto.getInsurName();
        String dept = dto.getDept();
        String year = beginTime.substring(0,4);

        Map<String, Object> resultMap = new HashMap<>();
        YbClnAvgParam clnAvgParam = callClnAvgParam(year, insurName);
        if(null == clnAvgParam){
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }

        List<YbSetlInfo> list = dao.selectClnSetlData(beginTime, endTime, insurName, dept);
        Map<String, List<YbSetlInfo>> setlMap = list.stream().collect(
                Collectors.groupingBy(YbSetlInfo::getDeptId, Collectors.toList()));

        List<Map<String, Object>> resultList = new ArrayList<>();
        for(Map.Entry<String, List<YbSetlInfo>> entry : setlMap.entrySet()){

            List<YbSetlInfo> infoList = entry.getValue();
            if(infoList.size() == 0){
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            int rs = 0;
            int inDays = 0;
            int dlRs = 0;
            BigDecimal zfy = BigDecimal.ZERO;
            BigDecimal ypf = BigDecimal.ZERO;
            BigDecimal zf = BigDecimal.ZERO;
            BigDecimal dlf = BigDecimal.ZERO;
            BigDecimal bal = BigDecimal.ZERO;
            map.put("deptId", entry.getKey());
            map.put("deptName", infoList.get(0).getDeptName());
            map.put("insurName", insurName);
            for(YbSetlInfo info : infoList){
                ++rs;
                inDays += info.getInDays();
                zfy = DecimalUtil.add(zfy, BigDecimal.valueOf(info.getMedfeeSumamt()));
                ypf = DecimalUtil.add(ypf, DecimalUtil.add(DecimalUtil.add(info.getChargeWesternMedicine(), info.getChargePatentMedicine()), info.getChargeHerbal()));
                zf = DecimalUtil.add(zf, BigDecimal.valueOf(info.getPsnPartAmt()));
                // false表示列为单列：盈亏额为0,无需计算
                boolean flag = true;
                if(BigDecimal.valueOf(info.getMedfeeSumamt()).compareTo(
                        (DecimalUtil.multiply(clnAvgParam.getAvgStandard(), clnAvgParam.getRates()))) >= 0){
                    ++dlRs;
                    dlf = DecimalUtil.add(dlf, BigDecimal.valueOf(info.getMedfeeSumamt()));
                    flag = false;
                }
                // 长沙县城职/居普通住院病人做了介入手术且手术+化疗同时进行病人也纳入单列
                if("长沙县城职普通住院".equals(insurName) || "长沙县城居普通住院".equals(insurName)){
                    // 是否用了介入手术材料并且是否同时做了化疗
                    if(isInterventionalProject(info.getPatNo(), info.getTimes(), info.getLedgerSn()) && isChemotherapy(info.getPatNo(), info.getTimes())){
                        flag = false;
                    }
                }
                if(flag){
                    bal = DecimalUtil.add(bal, DecimalUtil.minus(clnAvgParam.getAvgStandard(), BigDecimal.valueOf(info.getMedfeeSumamt())));
                }
            }
            map.put("zfy", zfy);
            map.put("rs", rs);
            map.put("ypf", ypf);
            map.put("zf", zf);
            map.put("inDays", inDays);
            map.put("dlRs", dlRs);
            map.put("dlf", dlf);
            map.put("bal", bal);
            // 次均费用
            map.put("cjfy", DecimalUtil.divide(zfy, BigDecimal.valueOf(Long.parseLong(String.valueOf(rs))), 2));
            // 平均住院天数
            map.put("avgDays", inDays/rs);
            // 床日费用
            map.put("crf", DecimalUtil.divide(zfy, BigDecimal.valueOf(Long.parseLong(String.valueOf(inDays))), 2));
            // 药品比
            map.put("ypbl", DecimalUtil.multiply(DecimalUtil.divide(ypf, zfy, 4), BigDecimal.valueOf(100)));
            // 自付比
            map.put("zfbl", DecimalUtil.multiply(DecimalUtil.divide(zf, zfy, 4), BigDecimal.valueOf(100)));
            resultList.add(map);
        }
        resultMap.put("insurName", insurName);
        resultMap.put("avgFee", clnAvgParam.getAvgStandard());
        resultMap.put("avgRates", clnAvgParam.getRates());
        resultMap.put("dlFee", DecimalUtil.multiply(clnAvgParam.getAvgStandard(), clnAvgParam.getRates()));
        resultMap.put("returnData", resultList);
        return ResultVoUtil.success(resultMap);
    }

    private boolean isChemotherapy(String patNo, Integer times) {
        List<Map<String, Object>> feeList = utilDao.selectChemotherapyDigan(patNo, times);
        if(feeList.size() > 0){
            log.info("住院号：{}, 住院次数：{}", patNo, times);
        }
        return feeList.size() != 0;
    }

    private boolean isInterventionalProject(String patNo, Integer times, Integer ledgerSn) {
        List<ZyDetailCharge> feeList = utilDao.selectInterventionalProject(patNo, times, ledgerSn, "0032%");
        return feeList.size() != 0;
    }

    /**
     * @description: 根据年份查询次均费用标准（今年查不到就差上一年的标准）
     * @author: hsh
     * @date: 2022/10/26 15:11
     * @param: [year, insurName]
     * @return: YbClnAvgParam
     **/
    private YbClnAvgParam callClnAvgParam(String year, String insurName) {
        YbClnAvgParam clnAvgParam = dao.selectClnAvgParam(year, insurName);
        if(null == clnAvgParam){
            year = String.valueOf(Integer.parseInt(year) - 1);
            clnAvgParam = dao.selectClnAvgParam(year, insurName);
        }
        return clnAvgParam;
    }

    public ResultVo<List<Map<String, Object>>> selectClnAvgFeeDoctor(YbkfShareDto dto) {
        String beginTime = dto.getStartTime();
        String endTime = dto.getEndTime();
        String insurName = dto.getInsurName();
        String year = beginTime.substring(0, 4);
        String dept = dto.getDept();

        YbClnAvgParam clnAvgParam = callClnAvgParam(year, insurName);
        if(null == clnAvgParam){
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }

        List<YbSetlInfo> list = dao.selectClnSetlData(beginTime, endTime, insurName, dept);
        Map<String, List<YbSetlInfo>> setlMap = list.stream().collect(
                Collectors.groupingBy(YbSetlInfo::getDoctorId, Collectors.toList()));

        List<Map<String, Object>> resultList = new ArrayList<>();
        for(Map.Entry<String, List<YbSetlInfo>> entry : setlMap.entrySet()){

            List<YbSetlInfo> infoList = entry.getValue();
            if(infoList.size() == 0){
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            int rs = 0;
            int inDays = 0;
            int dlRs = 0;
            BigDecimal zfy = BigDecimal.ZERO;
            BigDecimal ypf = BigDecimal.ZERO;
            BigDecimal zf = BigDecimal.ZERO;
            BigDecimal dlf = BigDecimal.ZERO;
            BigDecimal bal = BigDecimal.ZERO;
            map.put("deptId", infoList.get(0).getDeptId());
            map.put("deptName", infoList.get(0).getDeptName());
            map.put("doctorId", entry.getKey());
            map.put("doctor", infoList.get(0).getDoctor());
            map.put("insurName", insurName);
            for(YbSetlInfo info : infoList){
                ++rs;
                inDays += info.getInDays();
                zfy = DecimalUtil.add(zfy, BigDecimal.valueOf(info.getMedfeeSumamt()));
                ypf = DecimalUtil.add(ypf, DecimalUtil.add(DecimalUtil.add(info.getChargeWesternMedicine(), info.getChargePatentMedicine()), info.getChargeHerbal()));
                zf = DecimalUtil.add(zf, BigDecimal.valueOf(info.getPsnPartAmt()));
                // 计算单列
                boolean flag = true;
                if(BigDecimal.valueOf(info.getMedfeeSumamt()).compareTo(
                        (DecimalUtil.multiply(clnAvgParam.getAvgStandard(), clnAvgParam.getRates()))) >= 0){
                    ++dlRs;
                    dlf = DecimalUtil.add(dlf, BigDecimal.valueOf(info.getMedfeeSumamt()));
                    flag = false;
                }
                // 长沙县城职/居普通住院病人做了介入手术且手术+化疗同时进行病人也纳入单列
                if("长沙县城职普通住院".equals(insurName) || "长沙县城居普通住院".equals(insurName)){
                    // 是否用了介入手术材料并且是否同时做了化疗
                    if(isInterventionalProject(info.getPatNo(), info.getTimes(), info.getLedgerSn()) && isChemotherapy(info.getPatNo(), info.getTimes())){
                        flag = false;
                    }
                }
                if(flag){
                    bal = DecimalUtil.add(bal, DecimalUtil.minus(clnAvgParam.getAvgStandard(), BigDecimal.valueOf(info.getMedfeeSumamt())));
                }
            }
            map.put("zfy", zfy);
            map.put("rs", rs);
            map.put("ypf", ypf);
            map.put("zf", zf);
            map.put("inDays", inDays);
            map.put("dlRs", dlRs);
            map.put("dlf", dlf);
            map.put("bal", bal);
            // 次均费用
            map.put("cjfy", DecimalUtil.divide(zfy, BigDecimal.valueOf(Long.parseLong(String.valueOf(rs))), 2));
            // 平均住院天数
            map.put("avgDays", inDays/rs);
            // 床日费用
            map.put("crf", DecimalUtil.divide(zfy, BigDecimal.valueOf(Long.parseLong(String.valueOf(inDays))), 2));
            // 药品比
            map.put("ypbl", DecimalUtil.multiply(DecimalUtil.divide(ypf, zfy, 4), BigDecimal.valueOf(100)));
            // 自付比
            map.put("zfbl", DecimalUtil.multiply(DecimalUtil.divide(zf, zfy, 4), BigDecimal.valueOf(100)));
            resultList.add(map);
        }
        return ResultVoUtil.success(resultList);
    }

    public ResultVo<List<Map<String, Object>>> selectClnAvgFeePatient(YbkfShareDto dto) {

        String beginTime = dto.getStartTime();
        String endTime = dto.getEndTime();
        String insurName = dto.getInsurName();
        String year = beginTime.substring(0, 4);
        String dept = dto.getDept();
        String doctor = dto.getDoctor();

        YbClnAvgParam clnAvgParam = callClnAvgParam(year, insurName);
        if (null == clnAvgParam) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }

        List<YbSetlInfo> list = dao.selectClnAvgFeePatient(beginTime, endTime, insurName, dept, doctor);
        List<Map<String, Object>> resultList = new ArrayList<>();
        for(YbSetlInfo info : list){
            Map<String, Object> map = new HashMap<>();
            map.put("deptId", info.getDeptId());
            map.put("deptName", info.getDeptName());
            map.put("doctorId", info.getDoctorId());
            map.put("doctor", info.getDoctor());
            map.put("insurName", insurName);
            map.put("xm", info.getPsnName());
            map.put("zyh", info.getPatNo());
            map.put("zfy", info.getMedfeeSumamt());
            map.put("inDays", info.getInDays());
            map.put("zyzd", info.getMainDiagnosis());
            map.put("zyss", info.getMainOperation());
            BigDecimal ypf = DecimalUtil.add(DecimalUtil.add(info.getChargeWesternMedicine(), info.getChargePatentMedicine()), info.getChargeHerbal());
            map.put("ypf", ypf);
            map.put("zf", info.getPsnPartAmt());
            // 床日费用
            map.put("crf", DecimalUtil.divide(BigDecimal.valueOf(info.getMedfeeSumamt()), BigDecimal.valueOf(Long.parseLong(String.valueOf(info.getInDays()))), 2));
            // 药品比
            map.put("ypbl", DecimalUtil.multiply(DecimalUtil.divide(ypf, BigDecimal.valueOf(info.getMedfeeSumamt()), 4), BigDecimal.valueOf(100)));
            // 自付比
            map.put("zfbl", DecimalUtil.multiply(DecimalUtil.divide(BigDecimal.valueOf(info.getPsnPartAmt()), BigDecimal.valueOf(info.getMedfeeSumamt()), 4), BigDecimal.valueOf(100)));
            // 计算单列
            boolean flag = BigDecimal.valueOf(info.getMedfeeSumamt()).compareTo(
                    (DecimalUtil.multiply(clnAvgParam.getAvgStandard(), clnAvgParam.getRates()))) < 0;
            // 长沙县城职/居普通住院病人做了介入手术且手术+化疗同时进行病人也纳入单列
            if("长沙县城职普通住院".equals(insurName) || "长沙县城居普通住院".equals(insurName)){
                // 是否用了介入手术材料并且是否同时做了化疗
                if(isInterventionalProject(info.getPatNo(), info.getTimes(), info.getLedgerSn()) && isChemotherapy(info.getPatNo(), info.getTimes())){
                    flag = false;
                }
            }
            if(flag){
                BigDecimal bal = DecimalUtil.minus(clnAvgParam.getAvgStandard(), BigDecimal.valueOf(info.getMedfeeSumamt()));
                map.put("bal", bal);
                map.put("jslx", "普通病");
            } else {
                map.put("bal", 0);
                map.put("jslx", "单列");
            }
            resultList.add(map);
        }

        return ResultVoUtil.success(resultList);
    }

}
