package thyyxxk.webserver.service.dictionary.clinicalPathway;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.dao.his.dictionary.clinicalPathway.ClinicalPathwayDao;
import thyyxxk.webserver.dao.his.dictionary.clinicalPathway.ClinicalPathwayDayDao;
import thyyxxk.webserver.dao.his.dictionary.clinicalPathway.ClinicalPathwayOrderDao;
import thyyxxk.webserver.dao.his.dictionary.clinicalPathway.ClinicalPathwayWorkDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.dto.ClinicalPathwayDay;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.dto.ClinicalPathwayOrder;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.dto.ClinicalPathwayTemplates;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.dto.ClinicalPathwayWork;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.res.CreateOrderRes;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.vo.CreateOrderVo;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.vo.JyJcItemVo;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.vo.PathwayTemplatesVo;
import thyyxxk.webserver.entity.dictionary.pathwayTemplates.vo.TemplateDayVo;
import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.YaoPinXinXi;
import thyyxxk.webserver.service.PublicServer;
import thyyxxk.webserver.service.hutoolcache.DrugCache;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.utils.*;

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

@Service
@RequiredArgsConstructor
@Slf4j
public class ClinicalPathwayService {
    private final ClinicalPathwayDao dao;
    private final ClinicalPathwayDayDao dayDao;
    private final ClinicalPathwayWorkDao workDao;
    private final ClinicalPathwayOrderDao orderDao;
    public final static String[] workTYpe = new String[]{"zhenliao", "yzchangqi", "yzlinshi", "huli"};
    private final DrugCache drugCache;
    private final UserCache userCache;
    private final PublicServer publicServer;
    private final TransactionTemplate transactionTemplate;


    public List<PathwayTemplatesVo> getTemplatesToTree(String where) {
        String deptCode = StrUtil.format(" and dept_code = '{}'", userCache.getUserInfoByToken().getDeptCode());
        if (publicServer.needRule(38)) {
            deptCode = "";
        }
        if (StrUtil.isNotBlank(where)) {
            where = " and " + where;
        } else {
            where = "";
        }


        List<PathwayTemplatesVo> pathwayTemplates = dao.getPathwayTemplates(deptCode + where);
        return TreeUtilV2.create(pathwayTemplates)
                .parentId("parentCode")
                .id("id").execute();
    }


    public List<TemplateDayVo> getTemplateDayNotContent(String templateId) {
        List<TemplateDayVo> clinicalPathwayDays = dayDao.getDayByTemplateId(templateId);
        if (ListUtil.isBlank(clinicalPathwayDays)) {
            return new ArrayList<>();
        }
        setDate(clinicalPathwayDays);
        return clinicalPathwayDays;
    }

    public List<TemplateDayVo> getTemplateDay(String templateId) {
        List<TemplateDayVo> clinicalPathwayDays = getTemplateDayNotContent(templateId);
        if (ListUtil.isBlank(clinicalPathwayDays)) {
            return new ArrayList<>();
        }
        List<ClinicalPathwayWork> workByTemplateId = dayDao.getWorkByTemplateId(templateId);
        if (ListUtil.notBlank(workByTemplateId)) {
            Map<String, List<ClinicalPathwayWork>> workMap = workByTemplateId.stream().collect(
                    Collectors.groupingBy(
                            ClinicalPathwayWork::getDayId
                    )
            );
            // 循环每一天
            clinicalPathwayDays.forEach(day -> {
                Map<String, List<ClinicalPathwayWork>> tmpMap = getEmptyMap();

                List<ClinicalPathwayWork> clinicalPathwayWorks = workMap.get(day.getId());
                if (clinicalPathwayWorks != null) {
                    for (ClinicalPathwayWork item : clinicalPathwayWorks) {
                        List<ClinicalPathwayWork> compute = tmpMap.get(workTYpe[item.getType()]);
                        compute.add(item);
                    }
                }
                day.setExecute(tmpMap);
            });
        } else {
            for (TemplateDayVo item : clinicalPathwayDays) {
                item.setExecute(getEmptyMap());
            }
        }
        return clinicalPathwayDays;
    }

    public static void setDate(List<? extends ClinicalPathwayDay> value) {
        int upper = 0;
        for (int i = 0; i < value.size(); i++) {
            ClinicalPathwayDay item = value.get(i);
            if (i == 0) {
                item.setBeginDate(1);
                item.setEndDate(item.getExecutionDay());
            } else {
                item.setBeginDate(upper + 1);
                item.setEndDate(item.getBeginDate() + item.getExecutionDay() - 1);
            }
            upper = item.getEndDate();
        }

    }

    private Map<String, List<ClinicalPathwayWork>> getEmptyMap() {
        Map<String, List<ClinicalPathwayWork>> tmpMap = new HashMap<>();
        tmpMap.put("zhenliao", new ArrayList<>());
        tmpMap.put("yzchangqi", new ArrayList<>());
        tmpMap.put("yzlinshi", new ArrayList<>());
        tmpMap.put("huli", new ArrayList<>());
        return tmpMap;
    }


    public ClinicalPathwayWork addWorkItem(ClinicalPathwayWork params) {
        params.setId(SnowFlakeId.instance().nextId());
        params.setSort(workDao.getSortByDayId(params.getDayId()) + 1);
        workDao.insert(params);
        return params;
    }

    public void updateWorkItem(ClinicalPathwayWork params) {
        workDao.updateById(params);
    }

    public List<String> checkOrder(ClinicalPathwayOrder item) {
        List<String> error = new ArrayList<>();
        if (StrUtil.isBlank(item.getFrequCode())) {
            error.add("执行频率不能为空");
        }

        if ("00".equals(item.getSerial())) {
            if (StrUtil.isNotBlank(item.getParentNo())) {
                error.add("项目无法成组。");
            }
        } else {
            if (StrUtil.isBlank(item.getSupplyCode())) {
                error.add("给药方式不能为空");
            }
            if (StrUtil.isBlank(item.getDoseUnit())) {
                error.add("单位不能为空");
            }
            if (BigDecimal.ZERO.compareTo(item.getDrugQuan()) > 0) {
                error.add("领量不能小于 0 ");
            }
        }
        return error;
    }

    public ResultVo<Map<Integer, List<String>>> createOrderNo(CreateOrderRes res) {
        List<ClinicalPathwayOrder> list = res.getList();
        if (ListUtil.isBlank(list)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "无法上传空医嘱。");
        }
        Map<Integer, List<String>> error = new HashMap<>();

        // 不能有父医嘱的医嘱
        Set<String> workTypeSet = new HashSet<>();

        for (int i = 0; i < list.size(); i++) {
            ClinicalPathwayOrder item = list.get(i);
            List<String> strings = checkOrder(item);

            if (item.getType() == 0) {
                if (item.getDose() == null) {
                    error.compute(i + 1, (k, value) -> value == null ? new ArrayList<>() : value)
                            .add("一次剂量不能为空");
                }

                if (BigDecimal.ZERO.compareTo(item.getDose()) >= 0) {
                    error.compute(i + 1, (k, value) -> value == null ? new ArrayList<>() : value)
                            .add("一次剂量不能小于等于 0");
                }

                if (ListUtil.notBlank(strings)) {
                    error.put(i + 1, strings);
                }

                if (StrUtil.isBlank(item.getParentNo())) {
                    workTypeSet.add(item.getId());
                }

                if (item.getSerial().equals("00")) {
                    workTypeSet.add(item.getId());
                }
            } else {
                item.setParentNo(null);
            }
        }

        for (int i = 0; i < list.size(); i++) {
            ClinicalPathwayOrder item = list.get(i);
            if (workTypeSet.contains(item.getId()) && StrUtil.isNotBlank(item.getParentNo())) {
                error.compute(i + 1, (k, value) -> value == null ? new ArrayList<>() : value)
                        .add("该医嘱不能有父医嘱");
            }
        }

        if (!error.isEmpty()) {
            return ResultVoUtil.success(error);
        }

        insertWorkOrder(res);

        log.info("临床路径医嘱：{}", res);
        return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION);
    }


    public void insertWorkOrder(CreateOrderRes res) {
        orderDao.deleteOrderTemplateByWorkId(res.getWordId());
        Map<String, ClinicalPathwayOrder> keyCompare = new HashMap<>();
        ListUtil.batchList(res.getList(), ClinicalPathwayOrderDao.class, (mapper, item) -> {
            String id = SnowFlakeId.instance().nextId();
            keyCompare.put(item.getId(), item);
            item.setId(id);
            if (!item.getSerial().equals("00")) {
                String key = item.getOrderCode().trim() + item.getSerial().trim();
                DrugCache.YpInfo drug = drugCache.get(key);
                YaoPinXinXi info = drug.getInfo();
                item.setDrugVolume(info.getVolum());
                item.setDrugVolUnit(info.getVolUnit());
                item.setDrugWeight(info.getWeight());
                item.setDrugWeightUnit(info.getWeighUnit());
                item.setDrugOcc(getOcc(info, item.getDose(), item.getDoseUnit()));
                item.setMiniUnit(info.getMiniUnit());
                if (StrUtil.isBlank(item.getParentNo())) {
                    item.setParentNo(null);
                } else {
                    ClinicalPathwayOrder clinicalPathwayOrder = keyCompare.get(item.getParentNo());
                    if (clinicalPathwayOrder == null) {
                        item.setParentNo(null);
                        item.setExecUnit(null);
                    } else {
                        item.setParentNo(clinicalPathwayOrder.getId());
                        item.setExecUnit(clinicalPathwayOrder.getExecUnit());
                    }
                }
            } else {
                item.setDrugOcc(item.getDrugQuan());
                item.setParentNo(null);
            }
            item.setWorkId(res.getWordId());
            mapper.insert(item);
        });

    }

    public BigDecimal getOcc(YaoPinXinXi drug, BigDecimal dose, String doseUnit) {

        if (ObjUtil.equals(drug.getWeighUnit(), doseUnit)) {
            return DecimalUtil.divide(dose, drug.getWeight(), 2);
        }

        if (ObjUtil.equals(drug.getVolUnit(), doseUnit)) {
            return DecimalUtil.divide(dose, drug.getVolum(), 2);
        }

        if (ObjUtil.equals(drug.getPackUnit(), doseUnit)) {
            return DecimalUtil.divide(dose, drug.getPackSize(), 2);
        }

        return dose;
    }

    public List<CreateOrderVo> getOrderTemplateByWorkId(String workId) {
        return orderDao.getOrderTemplate(workId);
    }

    public List<CreateOrderVo> getOrderTemplateByDayId(String dayId) {
        return orderDao.getOrderTemplateByDayId(dayId);
    }


    /**
     * @param type 1-检验 2- 检查
     * @param key  搜索关键字
     * @return 项目
     */
    public List<JyJcItemVo> getJcJyItem(Integer type, String key) {
        return dao.getJcJyItem(type == 1 ? "jy_zd_item" : "jc_zd_item", type, StringUtil.isContainChinese(key));
    }

    /**
     * 预留此功能
     *
     * @param id 模板id
     * @return 提示
     */
    public ResultVo<String> copyClinicalPathway(String id, String name) {
        ClinicalPathwayTemplates templates = dao.selectById(id);
        if (templates == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "模板已经删除了");
        }

        String tmpId = templates.getId();

        ClinicalPathwayTemplates insert = new ClinicalPathwayTemplates();
        BeanUtil.copyProperties(templates, insert);
        insert.setId(SnowFlakeId.instance().nextId());
        insert.setName(name);
        insert.setUpdateCode(null);
        insert.setUpdateTime(null);
        dao.insert(insert);
        List<ClinicalPathwayDay> allDayByTemplateId = dao.getAllDayByTemplateId(tmpId);

        Map<String, String> dayMap = new HashMap<>();
        Map<String, String> works = new HashMap<>();
        // 复制每天
        ListUtil.batchList(allDayByTemplateId, ClinicalPathwayDayDao.class, (mapper, item) -> {
            String tid = SnowFlakeId.instance().nextId();
            dayMap.put(item.getId(), tid);
            item.setId(tid);
            item.setTemplateId(insert.getId());
            mapper.insert(item);
        });

        List<ClinicalPathwayWork> workByTemplateId = dao.getWorkByTemplateId(tmpId);

        // 复制工作内容
        ListUtil.batchList(workByTemplateId, ClinicalPathwayWorkDao.class, (mapper, item) -> {
            String tid = SnowFlakeId.instance().nextId();
            works.put(item.getId(), tid);
            item.setDayId(dayMap.get(item.getDayId()));
            item.setId(tid);
            mapper.insert(item);
        });

        for (Map.Entry<String, String> item : works.entrySet()) {
            List<ClinicalPathwayOrder> ordersByTemplateId = dao.getOrdersByTemplateId(item.getKey());
            CreateOrderRes res = new CreateOrderRes();
            res.setWordId(item.getValue());
            res.setList(ordersByTemplateId);
            insertWorkOrder(res);
        }

        return ResultVoUtil.success();
    }

    public ResultVo<String> delTemplate(String id) {
        ClinicalPathwayTemplates templates = dao.selectById(id);
        if (templates == null) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "可能已经被删除了。");
        }

        if (templates.getCreateCode().equals(TokenUtil.getInstance().getTokenUserId())) {
            dao.deleteById(id);
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_NOTIFICATION, "删除成功。");
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "创建人不是你无法删除。");
    }

}
