package thyyxxk.webserver.service.medicaladvice.medicamanage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.medicaladvice.medicamanage.MedicalManagementDao;
import thyyxxk.webserver.dao.his.medicaladvice.medicamanage.YzPrintRecDao;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.datamodify.YzActOrder;
import thyyxxk.webserver.entity.executeItem.NumberEnum;
import thyyxxk.webserver.entity.inpatient.patient.Patient;
import thyyxxk.webserver.entity.inpatient.patient.YzQueryBase;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.entity.medicaladvice.medicamanage.YzOrderParam;
import thyyxxk.webserver.entity.medicaladvice.medicamanage.YzPrintRec;
import thyyxxk.webserver.entity.medicaladvice.medicamanage.YzPrintVO;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYzActOrder;
import thyyxxk.webserver.service.hutoolcache.ExtraCache;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.service.inpatient.PatientService;
import thyyxxk.webserver.utils.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author:lihong
 * @Date: 2023/3/13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MedicalManagementService {
    private final MedicalManagementDao dao;
    private final PatientService patientService;
    private final YiZhuLuRuDao yiZhuLuRuDao;
    private final YzPrintRecDao yzPrintRecDao;
    private final UserCache userCache;
    private final ExtraCache extraCache;
    //打印分页数
    private static final int PRINT_PAGE_SIZE = 20;
    //长期 临时医嘱打印名称
    private static final String PRINT_NAME_ORD_LONG = "print_ord_long";
    private static final String PRINT_NAME_ORD_ONCE = "print_ord_once";


    public ResultVo<Map<String, Object>> cqYzPrint(YzOrderParam param) {
        return getPrinInfo(param);
    }

    public ResultVo<Map<String, Object>> lsYzPrint(YzOrderParam param) {
        return getPrinInfo(param);
    }

    private String getPageCondition(YzOrderParam param, String pageTemplate) {
        String pageCondition;
        AssertUtil.isnotBlank(param.getPrintType(), "请选择打印类型");
        if (param.getPrintType() == 1) {
            pageCondition = StrUtil.format(" isnull({},0)=0  ", pageTemplate);
        } else {
            AssertUtil.isnotBlank(param.getPageNum(), "请选择医嘱页码");
            if (param.getPrintType() == 2) {
                pageCondition = StrUtil.format("isnull({},0) ={}", pageTemplate, param.getPageNum());
            } else {
                pageCondition = StrUtil.format("isnull({},0) >={}", pageTemplate, param.getPageNum());
            }
        }
        return pageCondition;
    }

    private ResultVo<Map<String, Object>> getPrinInfo(YzOrderParam param) {
        Map<String, Object> map = new HashMap<>(2);
        List<YzPrintVO> yzPrintVOList;
        String tableName = NumberEnum.ONE.getCode().equals(param.getInOutStatusFlag()) ? "yz_inact_order" : "yz_act_order";
        if (param.getType() == 1) {
            //长期医嘱
            String pageCondition = getPageCondition(param, "a.print_page");
            yzPrintVOList = dao.getcqYzPrint(param.getPatNo(), param.getTimes(), pageCondition,tableName);
        } else {
            String pageCondition = getPageCondition(param, "a.print_page_once");
            yzPrintVOList = dao.getlsYzPrint(param.getPatNo(), param.getTimes(), pageCondition,tableName);
        }
        if (CollUtil.isNotEmpty(yzPrintVOList)) {
            List<YzPrintVO> childrenList = yzPrintVOList.stream().filter(o -> o.getParentNo() != null).collect(Collectors.toList());
            Map<Long, List<YzPrintVO>> groupMap = null;
            if (CollUtil.isNotEmpty(childrenList)) {
                groupMap = childrenList.stream().collect(Collectors.groupingBy(o -> o.getParentNo()));
            }
            for (YzPrintVO obj : yzPrintVOList) {
                obj.setOrderGroupNo("");
                obj.setDate(DateUtil.format(obj.getStartTime(), "MM-dd"));
                obj.setTime(DateUtil.format(obj.getStartTime(), "HH:mm"));
                obj.setStopDate(DateUtil.format(obj.getEndTime(), "MM-dd"));
                obj.setStopTime(DateUtil.format(obj.getEndTime(), "HH:mm"));
                obj.setModifierName(getUserName(obj.getModifier()));
                obj.setExecId2Name(getUserName(obj.getExecId2()
                ));
                obj.setExecName(getUserName(obj.getExecId()));
                obj.setFrequCode(StrUtil.replace(obj.getFrequCode(), "Always", "").replace("Once", ""));
                obj.setDoctorName(getUserName(obj.getDoctorCode()));
                obj.setNurseName(getUserName(obj.getNurseCode()));
                obj.setNewOrderName(StrUtil.replace(obj.getNewOrderName(), "诊疗项目", ""));
                obj.setExecTimeStr(obj.getExecTime() == null ? "" : DateUtil.format(obj.getExecTime(), "MM-dd HH:mm"));
                if (MapUtil.isNotEmpty(groupMap)) {
                    if (obj.getParentNo() == null && groupMap.containsKey(obj.getActOrderNo())) {
                        obj.setOrderGroupNo("┏");
                    } else if (obj.getParentNo() != null) {
                        List<YzPrintVO> yzPrintVOS = groupMap.get(obj.getParentNo());
                        if (obj.getActOrderNo() == yzPrintVOS.get(yzPrintVOS.size() - 1).getActOrderNo()) {
                            obj.setOrderGroupNo("┗");
                        } else {
                            obj.setOrderGroupNo("┃");
                        }
                    }
                }
            }
        }

        List<YzPrintVO> result = dealYzPrintVOList(param, yzPrintVOList);
        Patient patientInfo = getPatientBaseInfo(param.getPatNo(), param.getTimes(), param.getInOutStatusFlag());
        map.put("yzPrintVOList", result);
        map.put("patientInfo", patientInfo);
        return ResultVoUtil.success(map);
    }

    private List<YzPrintVO> dealYzPrintVOList(YzOrderParam param, List<YzPrintVO> yzPrintVOList) {
        List<YzPrintVO> result = new ArrayList<>();
        if (CollUtil.isEmpty(yzPrintVOList)) return result;
        if (param.getPrintType() == 1) {
            List<List<YzPrintVO>> splitList = CollUtil.split(yzPrintVOList, PRINT_PAGE_SIZE);
            if (splitList.get(splitList.size() - 1).size() <= PRINT_PAGE_SIZE) {
                addEmptyYzPrintVO(splitList.get(splitList.size() - 1), PRINT_PAGE_SIZE - splitList.get(splitList.size() - 1).size());
            }
            for (int i = 0; i < splitList.size(); i++) {
                result.addAll(splitList.get(i));
                YzPrintVO temp = setPageFlag(param, i + 1);
                result.add(temp);
            }
        } else if (param.getPrintType() == 2) {
            //    单页查询
            addAllPrintData(param, result, Convert.toInt(param.getPageNum()), yzPrintVOList, "当前页数据已超出打印范围,请重置打印页号");
        } else {
            //    查询某页后
            Map<Integer, List<YzPrintVO>> pageNoGroup = yzPrintVOList.stream().collect(Collectors.groupingBy(o -> o.getPageNo()));
            List<Integer> sortPageNo = CollUtil.newArrayList(pageNoGroup.keySet()).stream().sorted().collect(Collectors.toList());
            sortPageNo.forEach(pageNo -> {
                List<YzPrintVO> temp = pageNoGroup.get(pageNo);
                addAllPrintData(param, result, pageNo, temp, pageNo + "页数据已超出打印范围,请重置打印页号");
            });
        }
        return result;
    }

    private void addAllPrintData(YzOrderParam param, List<YzPrintVO> result, Integer pageNo, List<YzPrintVO> temp, String msg) {
        if (temp.size() <= PRINT_PAGE_SIZE) {
            addEmptyYzPrintVO(temp, PRINT_PAGE_SIZE - temp.size());
            result.addAll(temp);
            //添加页码
            YzPrintVO print = setPageFlag(param, pageNo);
            result.add(print);
        } else {
            throw new BizException(ExceptionEnum.INTERNAL_SERVER_ERROR, msg);
        }
    }

    @NotNull
    private YzPrintVO setPageFlag(YzOrderParam param, int pageNum) {
        YzPrintVO temp = new YzPrintVO();
        temp.setPageFlag("1");
        if (param.getType() == 1) {
            temp.setPrintPage(pageNum);
        } else {
            temp.setPrintPageOnce(pageNum);
        }
        return temp;
    }

    private void addEmptyYzPrintVO(List<YzPrintVO> list, int size) {
        if (size > 0) {
            for (int i = 0; i < size; i++) {
                YzPrintVO e = new YzPrintVO();
                e.setPageFlag("0");
                list.add(e);
            }
        }
    }


    private String getUserName(String code) {
        UserInfo userInfo = userCache.get(code);
        return userInfo == null ? "" : userInfo.getName();
    }


    public List<Patient> queryPatientInfo(String patNo, String ward, String inOutStatusFlag) {
        AssertUtil.isnotBlank(ward, "科室不能为空");
        QueryWrapper<?> query = new QueryWrapper<>();
        query.eq("a.ward", ward);
        query.likeRight(StringUtil.notBlank(patNo), "a.inpatient_no", patNo);
        String tableName;
        if ("1".equals(inOutStatusFlag)) {
            tableName = "zy_inactpatient";
        } else {
            tableName = "zy_actpatient";
        }

        List<Patient> patient = dao.queryPatientInfo(query, tableName);
        return patient;
    }

    /**
     * @description:查询医嘱
     * @author: lihong
     * @date: 2023/4/20 10:34
     * @param: yzQueryBase
     * @return: java.lang.Object
     **/
    public Map<String, Object> queryYz(YzQueryBase yzQueryBase) {
        Map<String, Object> result = new HashMap<>(3);
        List<XinZhenYzActOrder> yiZhuList = listYzActOrder(yzQueryBase);
        if (CollUtil.isNotEmpty(yiZhuList)) {
            List<XinZhenYzActOrder> childrenList = yiZhuList.stream().filter(o -> o.getParentNo() != null).collect(Collectors.toList());
            Map<Long, List<XinZhenYzActOrder>> groupMap = null;
            if (CollUtil.isNotEmpty(childrenList)) {
                groupMap = childrenList.stream().collect(Collectors.groupingBy(o -> Long.valueOf(o.getParentNo().longValue())));
            }
            for (XinZhenYzActOrder item : yiZhuList) {
                if ("00".equals(item.getSerial())) {
                    item.setGroupNoName("项目");
                    item.setSerialName("项目");
                } else {
                    if ("01".equals(item.getSerial())) {
                        item.setSerialName("小包装");
                    } else if ("99".equals(item.getSerial())) {
                        item.setSerialName("大包装");
                    }
                }
                if (MapUtil.isNotEmpty(groupMap)) {
                    if (item.getParentNo() == null && groupMap.containsKey(item.getActOrderNo().longValue())) {
                        item.setOrderGroup("┏");
                    } else if (item.getParentNo() != null) {
                        List<XinZhenYzActOrder> orderList = groupMap.get(item.getParentNo().longValue());
                        if (item.getActOrderNo() == orderList.get(orderList.size() - 1).getActOrderNo()) {
                            item.setOrderGroup("┗");
                        } else {
                            item.setOrderGroup("┃");
                        }
                    }
                }
            }

        }
        Patient patientInfo = getPatientBaseInfo(yzQueryBase.getPatNo(), yzQueryBase.getTimes(), yzQueryBase.getInOutStatusFlag());
        result.put("patientInfo", patientInfo);
        result.put("yzDataList", yiZhuList);
        return result;
    }

    @NotNull
    public QueryWrapper<?> getQueryWrapper(YzQueryBase yzQueryBase) {
        QueryWrapper<?> qw = new QueryWrapper<>();
        qw.eq("a.inpatient_no", yzQueryBase.getPatNo()).eq("a.admiss_times", yzQueryBase.getTimes());
        if ("3".equals(yzQueryBase.getStatusFlag())) {
            qw.inSql("a.status_flag", "'3','4'");
        } else if (StringUtil.notBlank(yzQueryBase.getStatusFlag()) && !"0".equals(yzQueryBase.getStatusFlag())) {
            qw.eq("a.status_flag", yzQueryBase.getStatusFlag());
        }
        /**显示范围 0 全部 1停止 2当前(查询确认和执行) 3 今天 */
        if ("1".equals(yzQueryBase.getQueryRange())) {
            qw.eq("a.status_flag", "5");
        } else if ("2".equals(yzQueryBase.getQueryRange())) {
            qw.inSql("a.status_flag", "'2','3','4'");
        } else if ("3".equals(yzQueryBase.getQueryRange())) {
            Date now = new Date();
            String nowStr = DateUtil.format(now, "yyyy-MM-dd");
            qw.ge("a.start_time", nowStr + " 00:00:00");
            qw.le("a.start_time", nowStr + " 23:59:59");
        }
        qw.orderByAsc("a.order_time");
        return qw;
    }


    public Patient getPatientBaseInfo(String patNo, Integer times, String inOutStatusFlag) {
        Patient patientInfo = patientService.getPatientBaseInfo(patNo, times, inOutStatusFlag);
        YzQueryBase yzQueryBase = new YzQueryBase();
        yzQueryBase.setPatNo(patNo);
        yzQueryBase.setTimes(times);
        yzQueryBase.setQueryRange("0");
        yzQueryBase.setStatusFlag("0");
        List<XinZhenYzActOrder> orderList = listYzActOrder(yzQueryBase);
        Map<String, List<String>> yzZdOrderItemMap = extraCache.getYzZdOrderItemMap();

        for (XinZhenYzActOrder item : orderList) {
            // 药品编码会重复
            if (!"00".equals(item.getSerial())) {
                continue;
            }

            if ("3".equals(item.getStatusFlag()) || "4".equals(item.getStatusFlag())) {
                if (item.getOrderName().contains("级护理")) {
                    patientInfo.setNursingLevel(item.getOrderName());
                }
            }
            if (yzZdOrderItemMap.get("病重").contains(item.getOrderCode())) {
                patientInfo.setCriticallyIllStatus("病重");
            }

            if (yzZdOrderItemMap.get("病危").contains(item.getOrderCode())) {
                patientInfo.setCriticallyIllStatus("病危");
            }
        }
        Integer count = dao.existOprt(patNo, times);
        if (count != null) {
            patientInfo.setOprtStatus("有手术");
        } else {
            patientInfo.setOprtStatus("无手术");
        }
        return patientInfo;
    }

    public List<XinZhenYzActOrder> listYzActOrder(YzQueryBase yzQueryBase) {
        QueryWrapper<?> qw = getQueryWrapper(yzQueryBase);
        List<XinZhenYzActOrder> yiZhuList = yiZhuLuRuDao.selectOrderNo(qw);
        EntityStringTrim.beanAttributeValueTrimList(yiZhuList);
        return yiZhuList;
    }

    public Map getTotalPageNUm(YzOrderParam param) {
        Map map = new HashMap(1);
        setYzActTableName(param);
        YzPrintVO data = dao.selectMaxPagaNo(param);
        if (param.getType() == 1) {
            map.put("total", data == null ? null : data.getPrintPage());
        } else {
            map.put("total", data == null ? null : data.getPrintPageOnce());
        }
        return map;
    }

    private void setYzActTableName(YzOrderParam param){
        String tableName = NumberEnum.ONE.getCode().equals(param.getInOutStatusFlag()) ? "yz_inact_order" : "yz_act_order";
        param.setTableName(tableName);
    }

    public ResultVo<String> recPrint(YzOrderParam param) {
        //--打印新增需要插入一条 print_ord_once  print_ord_long 一页20条, 请第几页进行续打
        //select * from    yz_print_rec where   inpatient_no ='0418368' and admiss_times =1 and print_name ='print_ord_once'
        //        --UPDATE yz_act_order SET print_page_once = 3 WHERE act_order_no = 17648285
        //        --update yz_print_rec set current_page =3 , last_row =14 where inpatient_no ='0418368' and admiss_times =1 and print_name ='print_ord_once'
        AssertUtil.isnotBlank(param.getPatNo(), "请选择一条病人");
        QueryWrapper query = new QueryWrapper();
        query.eq("inpatient_no", param.getPatNo());
        query.eq("admiss_times", param.getTimes());
        query.eq("print_name", param.getType() == 1 ? PRINT_NAME_ORD_LONG : PRINT_NAME_ORD_ONCE);
        YzPrintRec yzPrintRec = yzPrintRecDao.selectOne(query);
        String tableName = NumberEnum.ONE.getCode().equals(param.getInOutStatusFlag()) ? "yz_inact_order" : "yz_act_order";
        List<YzPrintVO> yzPrintVOS = param.getType() == 1 ? dao.getcqYzPrint(param.getPatNo(), param.getTimes(), " isnull(a.print_page,0)=0 ",tableName) : dao.getlsYzPrint(param.getPatNo(), param.getTimes(), " isnull(a.print_page_once,0)=0 ",tableName);
        YzPrintRec rec = new YzPrintRec();
        rec.setInpatientNo(param.getPatNo());
        rec.setAdmissTimes(param.getTimes());
        rec.setPrintName(param.getType() == 1 ? PRINT_NAME_ORD_LONG : PRINT_NAME_ORD_ONCE);
        int size;
        if (yzPrintRec == null) {
            size = yzPrintVOS.size();
        } else {
            Integer cur = yzPrintRec.getCurrentPage();
            Integer lr = yzPrintRec.getLastRow();
            int preSize = (cur - 1) * PRINT_PAGE_SIZE + lr;
            size = preSize + yzPrintVOS.size();
        }
        int currentPage = size % PRINT_PAGE_SIZE == 0 ? size / PRINT_PAGE_SIZE : size / PRINT_PAGE_SIZE + 1;
        int lastRow = size % PRINT_PAGE_SIZE == 0 ? PRINT_PAGE_SIZE : size % PRINT_PAGE_SIZE;
        rec.setCurrentPage(currentPage);
        rec.setLastRow(lastRow);
        if (yzPrintRec != null) {
            yzPrintRecDao.delete(query);
        }
        yzPrintRecDao.insert(rec);
        //print_page,print_page_once
        updatePageNo(yzPrintVOS, yzPrintRec, param.getType() == 1 ? " print_page" : " print_page_once");
        return ResultVoUtil.success();
    }

    private void updatePageNo(List<YzPrintVO> yzPrintVOS, YzPrintRec yzPrintRec, String printPageWhere) {
        if (yzPrintRec == null) {
            int curPage = 1;
            List<List<YzPrintVO>> split = CollUtil.split(yzPrintVOS, PRINT_PAGE_SIZE);
            for (List<YzPrintVO> item : split) {
                for (YzPrintVO temp : item) {
                    temp.setPageNo(curPage);
                }
                List<Long> orderNoList = item.stream().map(o -> o.getActOrderNo()).collect(Collectors.toList());
                String join = CollUtil.join(orderNoList, ",");
                dao.updatePrintPageNo(join, curPage, printPageWhere);
                ++curPage;
            }
        } else {
            int curPage = yzPrintRec.getCurrentPage();
            int lastRow = yzPrintRec.getLastRow();
            for (YzPrintVO item : yzPrintVOS) {
                ++lastRow;
                if (lastRow > PRINT_PAGE_SIZE) {
                    lastRow = 1;
                    ++curPage;
                }
                item.setPageNo(curPage);
            }
            Map<Integer, List<YzPrintVO>> pageNoGroup = yzPrintVOS.stream().collect(Collectors.groupingBy(o -> o.getPageNo()));
            for (Integer pageNo : pageNoGroup.keySet()) {
                List<Long> collect = pageNoGroup.get(pageNo).stream().map(o -> o.getActOrderNo()).collect(Collectors.toList());
                String join = CollUtil.join(collect, ",");
                dao.updatePrintPageNo(join, pageNo, printPageWhere);
            }
        }
    }


    public ResultVo<String> clearPrintPageNo(YzOrderParam param) {
        AssertUtil.isnotBlank(param.getPatNo(), "请选择一条病人");
        setYzActTableName(param);
        dao.updatePrintPage(param, param.getType() == 1 ? "print_page =null" : "print_page_once=null", param.getTableName());
        dao.updatePrintPage(param, param.getType() == 1 ? "print_page =null" : "print_page_once=null", "yz_erase_order");
        QueryWrapper query = new QueryWrapper();
        query.eq("inpatient_no", param.getPatNo());
        query.eq("admiss_times", param.getTimes());
        query.eq("print_name", param.getType() == 1 ? PRINT_NAME_ORD_LONG : PRINT_NAME_ORD_ONCE);
        yzPrintRecDao.delete(query);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "成功");
    }


    public List<YzActOrder> queryYzCheckData(YzQueryBase yzQueryBase) {
        if (NumberEnum.ThREE.getCode().equals(yzQueryBase.getQueryRange())) {
            Date now = new Date();
            yzQueryBase.setStartTime(DateUtil.formatDate(now) + " 00:00:00");
            yzQueryBase.setEndTime(DateUtil.formatDate(now) + " 23:59:59");
        }
        List<YzActOrder> list = dao.listYzCheckData(yzQueryBase);
        CommonUtil.BeanTrim(list);
        if (CollUtil.isNotEmpty(list)) {
            //组号填充
            Map<BigDecimal, String> orderGroupMap = new HashMap<>();
            Map<BigDecimal, List<YzActOrder>> parentNoMap = list.stream().collect(Collectors.groupingBy(item -> item.getParentNo()));
            for (BigDecimal parentNo : parentNoMap.keySet()) {
                List<YzActOrder> temp = parentNoMap.get(parentNo);
                if (temp.size() > 1) {
                    for (int i = 0; i < temp.size(); i++) {
                        if (i == 0) {
                            orderGroupMap.put(temp.get(i).getActOrderNo(), "┑");
                        } else if (i == temp.size() - 1) {
                            orderGroupMap.put(temp.get(i).getActOrderNo(), "┚");
                        }
                    }
                }
            }
            for (YzActOrder yzActOrder : list) {
                if ("00".equals(yzActOrder.getGroupNo())) {
                    yzActOrder.setOrderName(yzActOrder.getOrderName() + "  " + yzActOrder.getFrequCode());
                } else {
                    yzActOrder.setOrderName(yzActOrder.getOrderName() + " " + yzActOrder.getDose() + yzActOrder.getDoseUnit() + " " + yzActOrder.getFrequCode() + " " + yzActOrder.getSupplyCode());
                }
                if (orderGroupMap.get(yzActOrder.getActOrderNo()) != null) {
                    yzActOrder.setOrderGroup(orderGroupMap.get(yzActOrder.getActOrderNo()));
                }
            }
        }
        return list;
    }
}
