package com.diagbot.facade.data;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.diagbot.dto.AnalyzeRunDTO;
import com.diagbot.dto.RecordContentDTO;
import com.diagbot.dto.RespDTO;
import com.diagbot.dto.data.AMedicalRecordDTO;
import com.diagbot.dto.data.AMrContentDTO;
import com.diagbot.entity.*;
import com.diagbot.enums.IsDeleteEnum;
import com.diagbot.enums.ModeIdEnum;
import com.diagbot.facade.*;
import com.diagbot.service.impl.MedicalRecordServiceImpl;
import com.diagbot.service.impl.QcAbnormalServiceImpl;
import com.diagbot.util.*;
import com.diagbot.vo.AnalyzeRunVO;
import com.diagbot.vo.MedrecVo;
import com.diagbot.vo.QueryVo;
import com.diagbot.vo.data.*;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class AMedicalRecordFacade extends MedicalRecordServiceImpl {

    @Autowired
    @Qualifier("medicalRecordServiceImpl")
    private MedicalRecordServiceImpl medicalRecordService;

    @Autowired
    private ModelHospitalFacade modelHospitalFacade;

    @Autowired
    MedicalRecordFacade medicalRecordFacade;

    @Autowired
    private AMedicalRecordContentFacade aMedicalRecordContentFacade;

    @Autowired
    private BehospitalInfoFacade behospitalInfoFacade;

    @Autowired
    @Qualifier("qcAbnormalServiceImpl")
    private QcAbnormalServiceImpl qcAbnormalService;

    @Autowired
    private QcTypeFacade qcTypeFacade;

    @Autowired
    private ColumnFacade columnFacade;

    @Autowired
    private ReadProperties readProperties;

    @Autowired
    private BasHospitalInfoFacade basHospitalInfoFacade;

    @Autowired
    private AMedAbnormalInfoFacade aMedAbnormalInfoFacade;

    @Value("${encrypt.enable}")
    Boolean encryptFlag;

    @Value("${xml_analyse.enable}")
    Boolean xmlAnalyseFlag;

    @Value("${log_switch.enable}")
    private boolean logSwitch;

    private TZDBConn tzDBConn = new TZDBConn();

    /**
     * 终末质控-同步前一天的病历记录
     */
    public void executeMrRecord() {
        //String sql="select * from mr_medicalrecords  where cjcxrq>=dateadd(day,-2,getdate()) and cjcxrq<=getdate()";
        String sql = "select * from mr_medicalrecords  where cjcxrq>=(select CONVERT(varchar,GETDATE()-2,23)) and cjcxrq<(select CONVERT(varchar,GETDATE(),23)) ORDER BY cjcxrq DESC";
        List<MedicalRecord> medicalRecordList = tzDBConn.getMedicalRecord(sql);
        execute(medicalRecordList);
    }

    /**
     * 终末质控-通过接口更新病历记录
     *
     * @param list
     * @return
     */
    public RespDTO<List<AMedicalRecordDTO>> executeMrRecord(List<AMedicalRecordVO> list) {
        if (list != null && list.size() > 0) {
            //循环验证数据有效性
            for (AMedicalRecordVO aMedicalRecordVO : list) {
                if ("".equals(aMedicalRecordVO.getRecId())) {
                    return RespDTO.onError("请输入文书序号!");
                } else if (aMedicalRecordVO.getHospitalId() == null) {
                    return RespDTO.onError("请输入医院编码!");
                } else if ("".equals(aMedicalRecordVO.getBehospitalCode())) {
                    return RespDTO.onError("请输入病人住院编码!");
                }
            }

            //装载数据
            List<MedicalRecord> medicalRecordList = Lists.newArrayList();
            list.stream().forEach(s -> {
                MedicalRecord medicalRecord = new MedicalRecord();
                BeanUtil.copyProperties(s, medicalRecord);
                medicalRecord.setRecDate(DateUtil.parseDateTime(s.getRecDate()));
                medicalRecordList.add(medicalRecord);
            });
            execute(medicalRecordList);

            List<AMedicalRecordDTO> medicalRecordDTOList = BeanUtil.listCopyTo(list, AMedicalRecordDTO.class);
            return RespDTO.onSuc(medicalRecordDTOList);
        } else {
            return RespDTO.onError("未接收到数据!");
        }
    }

    public boolean hisDataDeal(HisDataDealVO hisDataDealVO) throws Exception {
        QueryWrapper<MedicalRecord> medicalRecordQe = new QueryWrapper<>();
        medicalRecordQe.eq("hospital_id", hisDataDealVO.getHospitalId());
        medicalRecordQe.eq("mode_id", hisDataDealVO.getModeId());
        medicalRecordQe.eq("is_deleted", IsDeleteEnum.N.getKey());
        medicalRecordQe.orderByDesc("rec_date","rec_id");
        if (hisDataDealVO.getRecIdList().size() > 0) {
            medicalRecordQe.in("rec_id", hisDataDealVO.getRecIdList());
        }
        List<MedicalRecord> medicalRecordList = medicalRecordService.list(medicalRecordQe);
            medicalRecordList.forEach(medicalRecord -> {
                        QueryWrapper<MedicalRecordContent> medicalRecordContentQe = new QueryWrapper<>();
                        medicalRecordContentQe.eq("hospital_id", hisDataDealVO.getHospitalId());
                        medicalRecordContentQe.eq("rec_id", medicalRecord.getRecId());
                        List<MedicalRecordContent> medicalRecordContentList = aMedicalRecordContentFacade.list(medicalRecordContentQe);

                        if (ListUtil.isEmpty(medicalRecordContentList)) {
                            return;
                        }

                        if (encryptFlag) {
                            try {
                                EncrypDES encrypDES = new EncrypDES();
                                for (MedicalRecordContent mrj : medicalRecordContentList) {
                                    mrj.setXmlText(encrypDES.decryptor(mrj.getXmlText()));
                                }
                            } catch (Exception e) {
                                return;
                            }
                        }

                        List<AMedicalRecordContentVO> contents = BeanUtil.listCopyTo(medicalRecordContentList, AMedicalRecordContentVO.class);
                        AMedicalRecordVO aMedicalRecordVO = new AMedicalRecordVO();
                        BeanUtil.copyProperties(medicalRecord, aMedicalRecordVO);
                        aMedicalRecordVO.setContents(contents);
                        List<AMedicalRecordVO> records = Lists.newArrayList();
                        records.add(aMedicalRecordVO);
                        AMrContentVO aMrContentVO = new AMrContentVO();
                        aMrContentVO.setRecords(records);
                        splicingParam(aMrContentVO);
                    }
            );
        return true;
    }


    /**
     * 特殊公共方法处理数据
     *
     * @param
     */
    public void specialDataWithKey(Boolean encryptFlag, List<RecordContentDTO> recordContentDTOS
    ) {

        if (encryptFlag) {
            try {
                EncrypDES encrypDES = new EncrypDES();
                for (RecordContentDTO mrj : recordContentDTOS) {
                    mrj.setXmlText(encrypDES.decryptor(mrj.getXmlText()));
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

    }


    /**
     * 入参结构拼接-仅支持接口对接的方式
     *
     * @param aMrContentVO
     */
    public void splicingParam(AMrContentVO aMrContentVO) {

            try {
                QueryVo queryVo = new QueryVo();
                List<MedrecVo> medreclist = Lists.newArrayList();

                List<AColumnContentVO> content = Lists.newArrayList();
                aMrContentVO.getRecords().stream().forEach(s -> {
                    queryVo.setHospitalId(s.getHospitalId().toString());
                    queryVo.setCid(basHospitalInfoFacade.getHosCode(s.getHospitalId()));
                    Long modeId ;
                    if (null == s.getModeId()) {
                        modeId = initModeId(s.getHospitalId(), s.getRecTypeId());
                    }else {
                        modeId = s.getModeId();
                    }
                    s.getContents().stream().forEach(item -> {
                        //拼接入参用于结构化解析
                        AColumnContentVO aColumnContentVO = new AColumnContentVO();
                        aColumnContentVO.setModeId(modeId);
                        aColumnContentVO.setStandModelName(ModeIdEnum.getName(Integer.parseInt(modeId.toString())));
                        aColumnContentVO.setRecId(s.getRecId());
                        aColumnContentVO.setRecTypeId(s.getRecTypeId());
                        aColumnContentVO.setRecTitle(s.getRecTitle());
                        aColumnContentVO.setXmlText(item.getXmlText());
                        aColumnContentVO.setBehospitalCode(s.getBehospitalCode());

                        content.add(aColumnContentVO);
                    });
                    Map<String, Object> map = new HashMap<String, Object>();
                    List<Map<String, Object>> returnData = new ArrayList<>();
                    String keyNname = ModeIdEnum.getName(Integer.parseInt(modeId.toString()));
                    Map<String, List<Map<String, Object>>> returnMap = new HashMap<>();
                    for (AColumnContentVO aColumnContentVO : content) {
                        try {
                            Map<String, Object> objectMap = MapUtil.objectToMap(aColumnContentVO);
                            returnData.add(objectMap);
                            returnMap.put(keyNname, returnData);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    map.put("content", returnData);
                    MedrecVo medrecVo = new MedrecVo();
                    medrecVo.setTitle(keyNname);
                    medrecVo.setContent(map);
                    medreclist.add(medrecVo);
                });
                queryVo.setMedrec(medreclist);

                columnFacade.analyseRec(queryVo);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                aMedAbnormalInfoFacade.saveAbnormalInfo("参数拼接", "", JSON.toJSONString(aMrContentVO), "", e.getMessage());
            }
        }


    /**
     * 运行质控-通过接口更新病历记录
     *
     * @param aMrContentVO
     * @return
     */
    public RespDTO<Map<String, Object>> executeMrRecordIng(AMrContentVO aMrContentVO) {
        if (aMrContentVO.getRecords() != null && aMrContentVO.getRecords().size() > 0) {
            AMrContentDTO aMrContentDTO = new AMrContentDTO();
            //循环验证数据有效性
            for (AMedicalRecordVO aMedicalRecordVO : aMrContentVO.getRecords()) {
                if ("".equals(aMedicalRecordVO.getRecId())) {
                    return RespDTO.onError("请输入文书序号!");
                } else if (aMedicalRecordVO.getHospitalId() == null) {
                    return RespDTO.onError("请输入医院编码!");
                } else if ("".equals(aMedicalRecordVO.getBehospitalCode())) {
                    return RespDTO.onError("请输入病人住院编码!");
                } else if ("".equals(aMedicalRecordVO.getRecTypeId())) {
                    return RespDTO.onError("请输入病历类别编号!");
                } else if ("".equals(aMedicalRecordVO.getRecTitle())) {
                    return RespDTO.onError("请输入病历标题!");
                } else if (aMedicalRecordVO.getContents() == null || aMedicalRecordVO.getContents().size() == 0) {
                    return RespDTO.onError("请输入文书详情!");
                }
            }
            //更新文书信息
            executeMrRecord(aMrContentVO.getRecords());

            aMrContentVO.getRecords().stream().forEach(s -> {
                //更新文书详情
                aMedicalRecordContentFacade.executeMrRecordContent(s.getContents());
            });

            //数据解析,评分规则等还未完整时不解析
            if(xmlAnalyseFlag){
                splicingParam(aMrContentVO);
            }
            //评分后返回结构体
            return mrIng(aMrContentVO);

        } else {
            return RespDTO.onError("未接收到数据!");
        }
    }

    /**
     * 评分后返回结构体
     *
     * @param aMrContentVO
     * @return
     */
    private RespDTO<Map<String, Object>> mrIng(AMrContentVO aMrContentVO) {
        String behospitalCode = aMrContentVO.getRecords().get(0).getBehospitalCode();
        Long hospitalId = aMrContentVO.getRecords().get(0).getHospitalId();
        MedicalRecord medicalRecord = new MedicalRecord();
        BeanUtil.copyProperties(aMrContentVO.getRecords().get(0), medicalRecord);
        Long modeId = initModeId(medicalRecord);
        if (aMrContentVO.getDockModeType().equals("0")) {
            Map<String, Object> map = new HashMap<String, Object>();
            List<AMedicalRecordDTO> medicalRecordDTOList = BeanUtil.listCopyTo(aMrContentVO.getRecords(), AMedicalRecordDTO.class);
            map.put("records", medicalRecordDTOList);
            return RespDTO.onSuc(map);
        } else if (aMrContentVO.getDockModeType().equals("1")) {
            if (modeId == 0 || modeId == null) {
                return RespDTO.onError("无对应的文书类型");
            }
            //页面模式
            String url = readProperties.getProcessQcUrl() + "?behospitalCode=" + behospitalCode + "&hospitalId=" + hospitalId + "&modeId=" + modeId;
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("url", url);
            return RespDTO.onSuc(map);
        } else if (aMrContentVO.getDockModeType().equals("2")) {
            AnalyzeRunVO analyzeRunVO = new AnalyzeRunVO();
            analyzeRunVO.setBehospitalCode(behospitalCode);
            analyzeRunVO.setHospitalId(hospitalId);
            analyzeRunVO.setModeId(modeId);
            AnalyzeRunDTO analyzeRunDTO = behospitalInfoFacade.analyzeRun(analyzeRunVO);
            Map<String, Object> map = new HashMap<String, Object>();
            if (analyzeRunDTO.getMsgDTOList().size() > 0) {
                map.put("analyze", analyzeRunDTO.getMsgDTOList());
            }
            //接口引擎模式
            return RespDTO.onSuc(map);
        } else {
            if (modeId == 0 || modeId == null) {
                return RespDTO.onError("无对应的文书类型");
            }
            //页面模式
            String url = readProperties.getProcessQcUrl() + "?behospitalCode=" + behospitalCode + "&hospitalId=" + hospitalId + "&modeId=" + modeId;

            AnalyzeRunVO analyzeRunVO = new AnalyzeRunVO();
            analyzeRunVO.setBehospitalCode(behospitalCode);
            analyzeRunVO.setHospitalId(hospitalId);
            analyzeRunVO.setModeId(modeId);
            AnalyzeRunDTO analyzeRunDTO = behospitalInfoFacade.analyzeRun(analyzeRunVO);
            Map<String, Object> map = new HashMap<String, Object>();
            if (analyzeRunDTO.getMsgDTOList().size() > 0) {
                map.put("url", url);
                map.put("analyze", analyzeRunDTO.getMsgDTOList());
            }
            return RespDTO.onSuc(map);
        }
    }

    public void execute(List<MedicalRecord> medicalRecordList) {
        try {
            List<MedicalRecord> addE = Lists.newLinkedList();
            List<MedicalRecord> updateE = Lists.newLinkedList();
            List<BehospitalInfo> behospitalInfoList = Lists.newLinkedList();
            List<QcAbnormal> qcAbnormalList = Lists.newLinkedList();
            if (medicalRecordList != null && medicalRecordList.size() > 0) {
                medicalRecordList.stream().forEach(s -> {
                    //初始化mode_id
                    Long modeId = initModeId(s);
                    if (modeId == Long.valueOf("0")) {
                        //新增类型到监测表中
                        QcAbnormal qcAbnormal = new QcAbnormal();
                        qcAbnormal.setHospitalId(s.getHospitalId());
                        qcAbnormal.setBehospitalCode(s.getBehospitalCode());
                        qcAbnormal.setType(1);
                        qcAbnormal.setDescription(s.getRecTitle());
                        qcAbnormal.setGmtCreate(new Date());
                        qcAbnormalList.add(qcAbnormal);
                    } else if (modeId == Long.valueOf("1")) {
                        BehospitalInfo behospitalInfo = behospitalInfoFacade.getOne(new QueryWrapper<BehospitalInfo>()
                                .eq("behospital_code", s.getBehospitalCode())
                                .eq("hospital_id", s.getHospitalId()), false);
                        if (behospitalInfo != null) {
                            //如果病人住院信息存在，更新对应的qc_type_id
                            Long qcTypeId = initQcTypeId(s);
                            behospitalInfo.setQcTypeId(qcTypeId);
                            behospitalInfoList.add(behospitalInfo);
                        }
                    }
                    s.setModeId(modeId);
                    //新增或修改
                    MedicalRecord mRecord = this.getOne(new QueryWrapper<MedicalRecord>()
                            .eq("rec_id", s.getRecId())
                            .eq("hospital_id", s.getHospitalId())
                            .eq("behospital_code", s.getBehospitalCode()), false);
                    if (mRecord != null) {
                        s.setGmtModified(new Date());
                        updateE.add(s);
                    } else {
                        s.setGmtCreate(new Date());
                        addE.add(s);
                    }
                });
            }
            if (addE.size() > 0) {
                medicalRecordService.saveBatch(addE);
            }
            if (updateE.size() > 0) {
                medicalRecordService.updateBatchByKey(updateE);
            }
            if (qcAbnormalList.size() > 0) {
                qcAbnormalService.saveBatch(qcAbnormalList);
            }
            if (behospitalInfoList.size() > 0) {
                behospitalInfoFacade.updateBatchByKey(behospitalInfoList);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            aMedAbnormalInfoFacade.saveAbnormalInfo("文书信息", "", JSON.toJSONString(medicalRecordList), "", e.getMessage());
        }

    }

    /**
     * 初始化质控类型ID
     *
     * @param medicalRecord
     * @return
     */
    private Long initQcTypeId(MedicalRecord medicalRecord) {
        Long qcTypeId = Long.valueOf("0");
        QcType qcType = qcTypeFacade.getOne(new QueryWrapper<QcType>()
                .eq("name", medicalRecord.getRecTitle())
                .eq("hospital_id", medicalRecord.getHospitalId())
                .eq("is_deleted", IsDeleteEnum.N));
        if (qcType != null && qcType.getDefaultModule() == 0) {
            qcTypeId = qcType.getId();
        } else {
            QcType qcTypeStand = qcTypeFacade.getOne(new QueryWrapper<QcType>()
                    .eq("default_module", 1)
                    .eq("hospital_id", medicalRecord.getHospitalId())
                    .eq("is_deleted", IsDeleteEnum.N));
            if (qcTypeStand != null) {
                qcTypeId = qcTypeStand.getId();
            }
        }
        return qcTypeId;
    }

    /**
     * 初始化模型ID
     *
     * @param medicalRecord
     * @return
     */
    private Long initModeId(MedicalRecord medicalRecord) {
        Long modeId = Long.valueOf("0");
        QueryWrapper<ModelHospital> wrapper = new QueryWrapper<>();
        wrapper.eq("hospital_id", medicalRecord.getHospitalId());
        //wrapper.eq("hospital_model_name", medicalRecord.getRecTitle());
        wrapper.eq("remark", medicalRecord.getRecTypeId());
        ModelHospital mode = modelHospitalFacade.getOne(wrapper, false);
        if (mode != null) {
            modeId = mode.getStandModelId();
        } else {
            modeId = Long.valueOf("0");
        }
        return modeId;
    }

    /**
     * 初始化模型ID
     *
     * @param hospitalId
     * @param recTypeId
     * @return
     */
    private Long initModeId(Long hospitalId, String recTypeId) {
        Long modeId = Long.valueOf("0");
        QueryWrapper<ModelHospital> wrapper = new QueryWrapper<>();
        wrapper.eq("hospital_id", hospitalId);
        //wrapper.eq("hospital_model_name", recTitle);
        wrapper.eq("remark", recTypeId);
        ModelHospital mode = modelHospitalFacade.getOne(wrapper, false);
        if (mode != null) {
            modeId = mode.getStandModelId();
        } else {
            modeId = Long.valueOf("0");
        }
        return modeId;
    }

    public RespDTO deleteFlag(ADeleteFlagVO aDeleteFlagVO) {
        try {
            //验证数据是否存在
            if (StringUtil.isEmpty(aDeleteFlagVO.getRecId())) {
                return RespDTO.onError("请输入文书序号!");
            } else if (aDeleteFlagVO.getHospitalId() == null) {
                return RespDTO.onError("请输入医院编码!");
            } else if (StringUtil.isEmpty(aDeleteFlagVO.getBehospitalCode())) {
                return RespDTO.onError("请输入病人住院编码!");
            } else {
                UpdateWrapper<MedicalRecord> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("rec_id", aDeleteFlagVO.getRecId())
                        .eq("hospital_id", aDeleteFlagVO.getHospitalId())
                        .eq("behospital_code", aDeleteFlagVO.getBehospitalCode())
                        .eq("is_deleted", IsDeleteEnum.N)
                        .set("is_deleted", IsDeleteEnum.Y)
                        .set("gmt_modified", DateUtil.now());

                Boolean flag = update(new MedicalRecord(), updateWrapper);
                if (flag) {
                    UpdateWrapper<MedicalRecordContent> updateWrapperContent = new UpdateWrapper<>();
                    updateWrapperContent.eq("rec_id", aDeleteFlagVO.getRecId())
                            .eq("hospital_id", aDeleteFlagVO.getHospitalId())
                            .eq("is_deleted", IsDeleteEnum.N)
                            .set("is_deleted", IsDeleteEnum.Y)
                            .set("gmt_modified", DateUtil.now());

                    Boolean flagContent = aMedicalRecordContentFacade.update(new MedicalRecordContent(), updateWrapperContent);
                    //aMedAbnormalInfoFacade.saveAbnormalInfo("文书内容-删除",JSON.toJSONString(aDeleteFlagVO),JSON.toJSONString(RespDTO.onSuc(flagContent)),"操作成功!");
                }
                //aMedAbnormalInfoFacade.saveAbnormalInfo("文书信息-删除",JSON.toJSONString(aDeleteFlagVO),JSON.toJSONString(RespDTO.onSuc(flag)),"操作成功!");
                return RespDTO.onSuc(flag);
            }
        } catch (Exception e) {
            aMedAbnormalInfoFacade.saveAbnormalInfo("文书-删除", "", JSON.toJSONString(aDeleteFlagVO), "", e.getMessage());
            return RespDTO.onError(e.getMessage());
        }
    }

}
