package com.emr.service.ipml;

import com.emr.dao.MedicalOverdueReportMapper;
import com.emr.dao.StatementMapper;
import com.emr.dto.MedicalOverdueReportDto;
import com.emr.dto.ThreeDaysFileDto;
import com.emr.entity.Emr_Dictionary;
import com.emr.entity.OffsetLimitPage;
import com.emr.entity.V_Count;
import com.emr.service.Emr_DictionaryService;
import com.emr.service.StatementService;
import com.emr.util.ListUtil;
import com.emr.util.Msg;
import com.emr.util.Setters;
import com.emr.vo.ExecuteVo;
import com.emr.vo.MedicalOverdueReportVo;
import com.emr.vo.ThreeDaysFileVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @ClassName StatementServiceImpl
 * @Description 报表实体类
 * @Author linjj
 * @Date 2024/1/11 14:31
 * @Version 1.0
 */
@Service
@Transactional
public class StatementServiceImpl implements StatementService {
    @Autowired
    StatementMapper statementMapper;
    @Autowired
    private Emr_DictionaryService emrDictionaryService;
    @Autowired
    private MedicalOverdueReportMapper medicalOverdueReportMapper;

    @Override
    public List<ThreeDaysFileVo> threeDaysFileList(ThreeDaysFileDto dto) {
        ArrayList<MedicalOverdueReportDto> dtos = new ArrayList<>();
        List<ThreeDaysFileVo> list = statementMapper.getThreeDaysFileList(dto);
        //格式化保留两位小数四舍五入
        DecimalFormat df = new DecimalFormat("#.00");
        //转换科室方法
        conversion(list);
        //及时合计方法
        day3Rate(dto, list);
        //2天及时合计方法
        day2Rate(dto, list);
        //计算每个科室有多少迟交病历
        deptNameLate(dto, list);
        //返修及时归档数量
        returnNum(dto, list);
        //返修总数
        returnTimelyNum(dto, list);
        //反馈病历数量（本）
        feedBackRecord(dto, list);
        //超期扣罚数量
        returnOverdueNum(dto, list);
        //2天内归档有反馈数（本）
        returnOverdue2Day(dto, list);
        for (ThreeDaysFileVo lists : list) {
            //为空填充0
            fillNum(lists);
            //计算迟交合计出院合计-及时合计
            int lateNum = lists.getOutNum() - lists.getDay3Rate();
            lists.setLateNum(lateNum);
            //初次及时归档率
            if (String.valueOf(lists.getDay3Rate()).equals("0")) {
                lists.setDay3RateSting("0%");
            } else {
                double day3Rate = (double) lists.getDay3Rate() / (double) lists.getOutNum();
                //计算科室kpi
                String kpi = df.format(day3Rate * 5);
                lists.setDeptNameLateKpi(kpi);
                lists.setDay3RateSting(df.format(day3Rate * 100) + "%");
            }
            //返修及时归档率计算
            if (String.valueOf(lists.getReturnNum()).equals("0")) {
                lists.setReturnNumString("0%");
            } else {
                double returnNum = (double) lists.getReturnNum() / (double) lists.getReturnTimelyNum();
                lists.setReturnNumString(df.format(returnNum * 100) + "%");
            }
            //计算归档病历迟交扣罚金额，每本每天*30元
            int i = lists.getDeptNameLate() * 30;
            lists.setDeptNameLate(i);
            //计算无反馈病历数量（本）出院数量-反馈病历数量
            lists.setNotFeedBackRecordNum(lists.getOutNum() - lists.getFeedBackRecordNum());
            //计算反馈病历扣罚金额
            lists.setFeedBackMoney(lists.getFeedBackRecordNum() * 30);
            //计算超期扣罚金额，返修每本超期天数综合*30
            lists.setReturnOverdueMoney(lists.getReturnOverdueDay() * 30);
            //3天归档奖励本数
            lists.setDay3RewardNum(lists.getNotFeedBackRecordNum());
            //计算2天归档病历无反馈数量（本），2天及时合计-2天归档有反馈数量
            lists.setNoReturnOverdue2Day(lists.getDay2Rate() - lists.getReturnOverdue2Day());
        }
        arrangeDto(list,dtos);
        int medicalOverdueReport = medicalOverdueReportMapper.getMedicalOverdueReport();
        //判断是否存在数据存在数据先清空后插入
        if (StringUtils.isNotBlank(String.valueOf(medicalOverdueReport))) {
            medicalOverdueReportMapper.delMedicalOverdueReport();
            medicalOverdueReportMapper.addMedicalOverdueReport(dtos);
        }else {
            medicalOverdueReportMapper.addMedicalOverdueReport(dtos);
        }
        return list;
    }

    @Override
    public OffsetLimitPage getMedicalOverdueReportList(Integer offset, Integer limit) {
        PageHelper.offsetPage(offset, limit);
        List<MedicalOverdueReportVo> list = medicalOverdueReportMapper.getMedicalOverdueReportList();
        return new OffsetLimitPage((Page) list);
    }

    @Override
    public Msg saveMedicalOverdueExecute(ThreeDaysFileDto dto) {
        int i = medicalOverdueReportMapper.saveMedicalOverdueExecute(dto);
        if (i==1){
            return Msg.success("执行计划修改成功");
        }
        return Msg.success("执行计划修改失败");
    }

    @Override
    public ExecuteVo executeList() {
        return medicalOverdueReportMapper.executeList();
    }

    //整理dto
    private static void arrangeDto(List<ThreeDaysFileVo> list,List<MedicalOverdueReportDto> dtos) {
        for (ThreeDaysFileVo lists : list) {
            MedicalOverdueReportDto medicalOverdueReportDto = new MedicalOverdueReportDto();
            medicalOverdueReportDto.setDeptCode(lists.getDeptCode());
            if (StringUtils.isNotBlank(lists.getDeptName())) {
                medicalOverdueReportDto.setDeptName(lists.getDeptName());
            }
            medicalOverdueReportDto.setOutNum(lists.getOutNum());
            medicalOverdueReportDto.setLateNum(lists.getLateNum());
            medicalOverdueReportDto.setDay3Rate(lists.getDay3Rate());
            medicalOverdueReportDto.setDay2Rate(lists.getDay2Rate());
            medicalOverdueReportDto.setDeptNameLate(lists.getDeptNameLate());
            medicalOverdueReportDto.setDay3RateSting(lists.getDay3RateSting());
            medicalOverdueReportDto.setReturnNumString(lists.getReturnNumString());
            medicalOverdueReportDto.setDeptNameLateKpi(lists.getDeptNameLateKpi());
            medicalOverdueReportDto.setFeedBackRecordNum(lists.getFeedBackRecordNum());
            medicalOverdueReportDto.setNotFeedBackRecordNum(lists.getNotFeedBackRecordNum());
            medicalOverdueReportDto.setFeedBackMoney(lists.getFeedBackMoney());
            medicalOverdueReportDto.setReturnOverdueNum(lists.getReturnOverdueNum());
            medicalOverdueReportDto.setReturnOverdueMoney(lists.getReturnOverdueMoney());
            medicalOverdueReportDto.setDay3RewardNum(lists.getDay3RewardNum());
            medicalOverdueReportDto.setNoReturnOverdue2Day(lists.getNoReturnOverdue2Day());
            dtos.add(medicalOverdueReportDto);
        }
    }

    //2天内归档有反馈数（本）
    private void returnOverdue2Day(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        List<ThreeDaysFileVo> returnOverdueList = statementMapper.returnOverdue2Day(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(returnOverdueList, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int returnOverdue2Day = codeMap.get(deptCode).getReturnOverdue2Day();
                p.setReturnOverdue2Day(returnOverdue2Day);
            }
        });
    }

    //超期扣罚数量
    private void returnOverdueNum(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        //填充0防止空指针异常
        for (ThreeDaysFileVo lists : list) {
            lists.setReturnOverdueNum(0);
            lists.setReturnOverdueDay(0);
        }
        List<ThreeDaysFileVo> returnOverdueList = statementMapper.returnOverdueNum(dto);
        if (returnOverdueList.size() > 0) {
            //根据科室code转换key。value
            Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(list, ThreeDaysFileVo::getDeptCode);
            Setters.<ThreeDaysFileVo>instance().list(returnOverdueList).cycleSetProperties(p -> {
                String deptCode = p.getDeptCode();
                if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                    //超期本数
                    codeMap.get(deptCode).setReturnOverdueNum(codeMap.get(deptCode).getReturnOverdueNum() + 1);
                    //超期天数
                    codeMap.get(deptCode).setReturnOverdueDay(codeMap.get(deptCode).getReturnOverdueDay() + p.getReturnOverdueDay() - dto.getDay());
                }
            });
        }
    }

    //反馈病历数量（本）
    private void feedBackRecord(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        List<ThreeDaysFileVo> feedBackRecordList = statementMapper.feedBackRecord(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(feedBackRecordList, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int feedBackRecordNum = codeMap.get(deptCode).getFeedBackRecordNum();
                p.setFeedBackRecordNum(feedBackRecordNum);
            }
        });
    }

    //返修总数
    private void returnTimelyNum(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        List<ThreeDaysFileVo> returnTimelyNumList = statementMapper.returnTimelyNum(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(returnTimelyNumList, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int returnTimelyNum = codeMap.get(deptCode).getReturnTimelyNum();
                p.setReturnTimelyNum(returnTimelyNum);
            }
        });
    }

    //返修及时归档数量
    private void returnNum(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        List<ThreeDaysFileVo> returnNumList = statementMapper.getReturnNum(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(returnNumList, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int returnNum = codeMap.get(deptCode).getReturnNum();
                p.setReturnNum(returnNum);
            }
        });
    }

    //计算每个科室有多少天迟交病历
    private void deptNameLate(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        for (ThreeDaysFileVo vo : list) {
            vo.setDeptNameLate(0);
        }
        List<ThreeDaysFileVo> lateNumList = statementMapper.getLateNum(dto);
        if (lateNumList.size() > 0) {
            //根据科室code转换key。value
            Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(list, ThreeDaysFileVo::getDeptCode);
            Setters.<ThreeDaysFileVo>instance().list(lateNumList).cycleSetProperties(p -> {
                String deptCode = p.getDeptCode();
                if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                    int lateNum = p.getLateNum();
                    if (lateNum != 0) {
                        codeMap.get(deptCode).setDeptNameLate(codeMap.get(deptCode).getDeptNameLate() + lateNum - dto.getDay());
                    }
                }
            });
        }
    }

    //2天及时合计方法
    private void day2Rate(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        //2天及时合计
        List<ThreeDaysFileVo> day2Rate1 = statementMapper.getDay2Rate(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(day2Rate1, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int day2Rate = codeMap.get(deptCode).getDay2Rate();
                p.setDay2Rate(day2Rate);
            }
        });
    }

    //即使合计方法
    private void day3Rate(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list) {
        List<ThreeDaysFileVo> day3Rate1 = statementMapper.getDay3Rate(dto);
        //根据科室code转换key。value
        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(day3Rate1, ThreeDaysFileVo::getDeptCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                int day3Rate = codeMap.get(deptCode).getDay3Rate();
                p.setDay3Rate(day3Rate);
            }
        });
    }


    private static void fillNum(ThreeDaysFileVo list) {
        if (StringUtils.isBlank(String.valueOf(list.getDay3Rate()))) {
            list.setDay3Rate(0);
        }
        if (StringUtils.isBlank(String.valueOf(list.getReturnNum()))) {
            list.setReturnNum(0);
        }
        if (StringUtils.isBlank(String.valueOf(list.getDeptNameLate()))) {
            list.setDeptNameLate(0);
        }
        if (StringUtils.isBlank(String.valueOf(list.getFeedBackRecordNum()))) {
            list.setFeedBackRecordNum(0);
        }
        if (StringUtils.isBlank(String.valueOf(list.getReturnOverdueDay()))) {
            list.setReturnOverdueDay(0);
        }
        if (StringUtils.isBlank(String.valueOf(list.getReturnOverdue2Day()))) {
            list.setReturnOverdue2Day(0);
        }

    }


    //转换科室
    private void conversion(List<ThreeDaysFileVo> list) {
        //科室名称转换
        Emr_Dictionary dic = new Emr_Dictionary();
        dic.setEffective(1);
        dic.setTypecode("dept_code");
        List<Emr_Dictionary> dicList = emrDictionaryService.dicByTypeCode(dic);
        //转换科室
        Map<String, Emr_Dictionary> codeMap = ListUtil.toMap(dicList, Emr_Dictionary::getCode);
        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
            String deptCode = p.getDeptCode();
            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
                String deptName = codeMap.get(deptCode).getName();
                p.setDeptName(deptName);
            }
        });
    }

    //    //3天归档奖励本书
//    private void day3RewardNum(ThreeDaysFileDto dto, List<ThreeDaysFileVo> list){
//        List<ThreeDaysFileVo> day3RewardLiset = statementMapper.day3RewardNum(dto);
//        //根据科室code转换key。value
//        Map<String, ThreeDaysFileVo> codeMap = ListUtil.toMap(day3RewardLiset, ThreeDaysFileVo::getDeptCode);
//        Setters.<ThreeDaysFileVo>instance().list(list).cycleSetProperties(p -> {
//            String deptCode = p.getDeptCode();
//            if (StringUtils.isNotBlank(deptCode) && codeMap.containsKey(deptCode)) {
//                int day3RewardNum = codeMap.get(deptCode).getDay3RewardNum();
//                p.setDay3RewardNum(day3RewardNum);
//            }
//        });
//    }
}
