package thyyxxk.webserver.service.casefrontsheet;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.sidicts.Insutype;
import thyyxxk.webserver.constants.sidicts.MedType;
import thyyxxk.webserver.dao.his.LoginDao;
import thyyxxk.webserver.dao.his.casefrontsheet.BasSelectOverviewDao;
import thyyxxk.webserver.dao.his.casefrontsheet.CaseFrontSheetDao;
import thyyxxk.webserver.dao.his.casefrontsheet.SheetCreatedDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.casefrontsheet.*;
import thyyxxk.webserver.entity.covid.Region;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.service.externalhttp.PowersiSrvc;
import thyyxxk.webserver.utils.*;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class CaseFrontSheetMainService {
    private static ConcurrentHashMap<String, List<CodeName>> allDictionary;
    private final CaseFrontSheetDao dao;
    private final SheetCreatedDao createdDao;
    private final BasSelectOverviewDao basDao;
    private final LoginDao userDao;
    private final PowersiSrvc srvc;

    public CaseFrontSheetMainService(SheetCreatedDao createdDao, CaseFrontSheetDao dao,
                                     BasSelectOverviewDao basDao, LoginDao userDao, PowersiSrvc srvc) {
        this.dao = dao;
        this.createdDao = createdDao;
        this.basDao = basDao;
        this.userDao = userDao;
        this.srvc = srvc;
        if (allDictionary == null) {
            allDictionary = new ConcurrentHashMap<>();
        }
    }

    public ResultVo<Map<String, List<CodeName>>> getAllDictionary() {
        if (allDictionary.isEmpty()) {
            allDictionary.put("getMarriageCode", createdDao.getMarriageCode());
            allDictionary.put("getSexCode", createdDao.getSexCode());
            allDictionary.put("getAdmissWay", createdDao.getAdmissWay());
            allDictionary.put("getBloodType", createdDao.getBloodType());
            allDictionary.put("getAnaesthesia", createdDao.getAnaesthesia());
            allDictionary.put("getOperateScale", createdDao.getOperateScale());
            allDictionary.put("getAdmissStatus", createdDao.getAdmissStatus());
            allDictionary.put("getDisAdmissStatus", createdDao.getDisAdmissStatus());
            allDictionary.put("getCutHealGrade", createdDao.getCutHealGrade());
            allDictionary.put("getDisdiagStatus", createdDao.getDisdiagStatus());
            allDictionary.put("getHbsag", createdDao.getHbsag());
            allDictionary.put("getDiagConform", createdDao.getDiagConform());
            allDictionary.put("getDisdiagType", createdDao.getDisdiagType());
            allDictionary.put("getPatientStatus", createdDao.getPatientStatus());
            allDictionary.put("getQualityLevel", createdDao.getQualityLevel());
            allDictionary.put("getZyDismissWay", createdDao.getZyDismissWay());
            allDictionary.put("getTumorLevelT", createdDao.getTumorLevelT());
            allDictionary.put("getTumorLevelN", createdDao.getTumorLevelN());
            allDictionary.put("getTumorLevelM", createdDao.getTumorLevelM());
            allDictionary.put("getTumorLevel", createdDao.getTumorLevel());
            allDictionary.put("getRelations", createdDao.getRelations());
            List<CodeName> temp = new ArrayList<>();
            temp.add(new CodeName());
            temp.addAll(createdDao.getStatutoryEpidemic());
            allDictionary.put("getStatutoryEpidemic", temp);
            allDictionary.put("getClinicalPathwayManagement", createdDao.getClinicalPathwayManagement());
            allDictionary.put("getDrgsManagement", createdDao.getDrgsManagement());
            allDictionary.put("getCaseClassification", createdDao.getCaseClassification());
            allDictionary.put("getOccupation", createdDao.getOccupation());
            allDictionary.put("getCountry", createdDao.getCountry());
            allDictionary.put("getNation", createdDao.getNation());
            allDictionary.put("getPayMethod", createdDao.getPayMethod());
        }
        return ResultVoUtil.success(allDictionary);
    }

    public ResultVo<String> resetDictionary() {
        allDictionary.clear();
        return ResultVoUtil.success();
    }

    @Scheduled(cron = "0 0 3 * * ?")
    public void refreshDictionary() {
        resetDictionary();
    }

    public ResultVo<List<CodeName>> getUserWards() {
        String code = TokenUtil.getTokenUserId();
        List<Integer> roles = createdDao.selectUserRoles(code);
        List<CodeName> list;
        if (roles.contains(7) || roles.contains(1)) {
            list = createdDao.getAllWards();
        } else {
            list = createdDao.getUserWards(code);
        }
        list.removeIf(Objects::isNull);
        return ResultVoUtil.success(list);
    }

    public ResultVo<List<CodeName>> getAllWards() {
        return ResultVoUtil.success(createdDao.getAllWards());
    }

    public ResultVo<List<SheetOverview>> getPatientOverview(String ward) {
        return ResultVoUtil.success(dao.getPatientOverview(ward));
    }

    public ResultVo<List<SheetOverview>> getOutPatient(GetOutSheet param) {
        param.setEnd(param.getEnd() + " 23:59:59");
        if (StringUtil.isBlank(param.getWard())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请选择科室！");
        }
        return ResultVoUtil.success(dao.getOutPatients(param));
    }

    /**
     * 查询病案首页汇总
     *
     * @param param 查询的条件
     * @return 返回数据
     */
    public ResultVo<GetBasOverviewRet> getOutPatientForBas(GetOutSheet param) {
        GetBasOverviewRet ret = new GetBasOverviewRet();
        if (StringUtil.notBlank(param.getWard())) {
            int cd = dao.getCDBlfxCount(param.getWard());
            int all = dao.getAllDisPatientCount(param.getWard());
            if (cd == 0 || all == 0) {
                ret.setCdPercentage("0.00%");
            } else {
                ret.setCdPercentage(DecimalUtil.getPercent(cd, all));
            }
        }
        if (StringUtil.notBlank(param.getStart())) {
            param.setStart(param.getStart() + " 00:00:00");
        }
        if (StringUtil.notBlank(param.getEnd())) {
            param.setEnd(param.getEnd() + " 23:59:59");
        }
        List<SheetOverview> list;
        if (StringUtil.notBlank(param.getBah())) {
            if (param.getFileStatus() == 0) {
                list = basDao.selectPatientsForBasByBah(param);
                if (list.isEmpty()) {
                    list = basDao.selectSignApply(param.getBah(), param.getFileStatus());
                    if (list.isEmpty()) {
                        return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有找到此患者的未归档病案。");
                    }
                }
            } else {
                list = basDao.selectPatientsFromSignedBase(param);
                if (list.isEmpty()) {
                    return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有找到此患者的已归档病案。");
                }
            }
            if (param.getLateFlag() != 3) {
                list.removeIf(item -> !item.getLateFlag().equals(param.getLateFlag()));
            }
            ret.setList(list);
            return ResultVoUtil.success(ret);
        }
        if (StringUtil.notBlank(param.getWard())) {
            if (param.getFileStatus() == 0) {
                list = basDao.selectPatientsForBasByWard(param);
            } else {
                list = basDao.selectPatientsForBasByWard2(param);
            }
            if (param.getLateFlag() != 3) {
                list.removeIf(item -> !item.getLateFlag().equals(param.getLateFlag()));
            }
            ret.setList(list);
            return ResultVoUtil.success(ret);
        }
        if (param.getFileStatus() == 0) {
            list = basDao.selectPatientsForBasByFileStatus(param);
        } else {
            list = basDao.selectPatientsForBasByFileStatus2(param);
        }
        if (param.getLateFlag() != 3) {
            list.removeIf(item -> !item.getLateFlag().equals(param.getLateFlag()));
        }
        ret.setList(list);
        return ResultVoUtil.success(ret);
    }

    public ResultVo<CaseFrontsheetMain> getPatientInfo(SheetOverview overview) {
        CaseFrontsheetMain sheet;
        String bah = overview.getBah();
        Integer times = overview.getTimes();
        StandardAddressMember standardAddressMember = getStandardAddressMember(bah);
        int fileStatus = overview.getFileStatus();
        if (fileStatus == 1) {
            sheet = dao.selectSignedSheetMain(bah, times);
            if (null != sheet) {
                sheet.setDisdiagList(getSheetDisDiags(bah, times, fileStatus));
                sheet.setSurgeryList(getSheetSurgeries(bah, times, fileStatus));
                if (null != standardAddressMember) {
                    sheet.setStandardAddress(standardAddressMember.makeStandardAddress());
                }
                if (sheet.getAge() == 0 && null == sheet.getAgeDays()) {
                    sheet.setAgeDays(DateUtil.calculateNewBornAge(sheet.getBirthDate(), sheet.getAdmissDate()));
                    dao.updateNewBornAge(bah, times, sheet.getAgeDays());
                }
                if (StringUtil.isBlank(sheet.getMedType())) {
                    String psnmedtype = dao.selectMedType(sheet.getBah(), sheet.getAdmissTimes());
                    MedType medType = MedType.get(psnmedtype);
                    if (null != medType) {
                        sheet.setMedType(psnmedtype);
                        sheet.setMedTypeName(medType.getName());
                    }
                }
                return ResultVoUtil.success(sheet);
            }
        }
        int flag = overview.getInOutFlag();
        if (flag == 2) {
            flag = dao.selectActCount(bah, times) > 0 ? 1 : 2;
        }
        sheet = dao.getAPatientMi(bah);
        CaseFrontsheetMain sheet1 = dao.getZyLedgerFile(bah, times);
        CaseFrontsheetMain sheet2 = flag == 1 ? dao.getZyActPatient("zy_actpatient", "yz_act_order", bah, times) :
                dao.getZyActPatient("zy_inactpatient", "yz_inact_order", bah, times);
        if (null == sheet2) {
            sheet2 = flag == 1 ? dao.getZyActPatient("zy_inactpatient", "yz_inact_order", bah, times) :
                    dao.getZyActPatient("zy_actpatient", "yz_act_order", bah, times);
        }
        sheet.setAge(DateUtil.calculateAge(sheet.getBirthDate(), sheet2.getAdmissDate()));
        if (null != sheet.getAge() && sheet.getAge() == 0) {
            sheet.setAgeDays(DateUtil.calculateNewBornAge(sheet.getBirthDate(), sheet2.getAdmissDate()));
        }
        if (StringUtil.isBlank(sheet2.getMedType())) {
            String injurySerialNo = dao.selectInjurySerialNo(bah, times);
            if (StringUtil.notBlank(injurySerialNo)) {
                sheet2.setMedType("42");
            }
        }
        sheet2.setMedTypeName(MedType.getName(sheet2.getMedType()));
        sheet2.setInsutype(Insutype.getName(sheet2.getInsutype()));
        final int hasInfant = dao.getInfant(bah, times);
        sheet2.setHasInfant(String.valueOf(hasInfant));
        if (null == sheet2.getDismissDate()) {
            final Date dismissDate = flag == 1 ?
                    dao.getDismissDateFromYzActOrder("yz_inact_order", bah, times)
                    : dao.getDismissDateFromYzActOrder("yz_act_order", bah, times);
            sheet2.setDismissDate(dismissDate);
        }
        CaseFrontsheetMain sheet3 = dao.getBatjBa1(bah, times);
        if (sheet3 == null) {
            if (dao.isBatjBa1Exist(bah, times) == 0) {
                dao.createBatjBa1(bah, times, sheet.getName(), sheet2.getAdmissDate(),
                        sheet2.getAdmissDept(), sheet2.getAdmissWard());
                log.info("insert batjBa1>>> " + bah + ", " + times);
            }
        }
        CaseFrontsheetMain sheet4 = flag == 1 ? dao.getBatjBa2ForInPatient(bah, times) :
                dao.getBatjBa2ForOutPatient(bah, times);
        if (sheet4 == null) {
            if (dao.isBatjBa2Exist(bah, times) == 0) {
                dao.createBatjBa2(bah, times);
                log.info("insert batjBa2>>> " + bah + ", " + times);
            }
        }
        mergeObject(sheet1, sheet);
        mergeObject(sheet2, sheet);
        mergeObject(sheet3, sheet);
        mergeObject(sheet4, sheet);
        if (dao.getDismissOrder(bah, times) > 0) {
            sheet.setZyDismissWay("0");
        }
        if (dao.getDeathOrder(bah, times) > 0) {
            sheet.setZyDismissWay("4");
        }
        Integer days = DateUtil.daysBetween(sheet.getDismissDate(), sheet.getAdmissDate());
        if (0 == days) {
            days = 1;
        }
        if (days > 0) {
            sheet.setAdmissDays(String.valueOf(days));
        }

        if (null == sheet.getQualityControlDate()) {
            sheet.setQualityControlDate(new Date());
        }
        sheet.setDisdiagList(getSheetDisDiags(bah, times, fileStatus));
        sheet.setSurgeryList(getSheetSurgeries(bah, times, fileStatus));
        if (null != standardAddressMember) {
            sheet.setStandardAddress(standardAddressMember.makeStandardAddress());
            sheet.setLivePlaceCombo(standardAddressMember.makeAddressCombo() + sheet.getLivePlace());
        } else {
            sheet.setLivePlaceCombo(sheet.getLivePlace());
        }
        return ResultVoUtil.success(sheet);
    }

    private StandardAddressMember getStandardAddressMember(String bah) {
        StandardAddressMember member = dao.selectStandardAddressMember(bah);
        if (null != member) {
            return member;
        }
        String socialNo = dao.selectSocialNo(bah);
        if (null == socialNo || socialNo.trim().length() < 15) {
            return null;
        }
        Integer district;
        try {
            district = Integer.parseInt(socialNo.substring(0, 6));
        } catch (Exception e) {
            return null;
        }
        Region city = dao.selectParentRegion(district);
        if (null == city) {
            return null;
        }
        Region province = dao.selectParentRegion(city.getCode());
        if (null == province) {
            return null;
        }
        member = new StandardAddressMember();
        member.setCityCode(city.getCode());
        member.setCityName(city.getName());
        member.setDistrictCode(district);
        member.setDistrictName(dao.selectRegionName(district));
        member.setProvinceCode(province.getCode());
        member.setProvinceName(province.getName());
        return member;
    }

    private List<CaseFrontsheetDisdiag> getSheetDisDiags(String bah, int times, int status) {
        List<CaseFrontsheetDisdiag> disdiags = status == 1 ?
                dao.selectSignedSheetDiags(bah, times) : dao.getDisdiags(bah, times);
        if (disdiags == null) {
            disdiags = new ArrayList<>();
        }
        while (disdiags.size() < 27) {
            disdiags.add(new CaseFrontsheetDisdiag());
        }
        return disdiags;
    }

    private List<CaseFrontsheetSurgery> getSheetSurgeries(String bah, int times, int status) {
        List<CaseFrontsheetSurgery> surgeries = status == 1 ?
                dao.selectSignedSheetSurgeries(bah, times) : dao.getSurgeries(bah, times);
        if (surgeries == null) {
            surgeries = new ArrayList<>();
        }
        while (surgeries.size() < 5) {
            surgeries.add(new CaseFrontsheetSurgery());
        }
        return surgeries;
    }

    private void mergeObject(CaseFrontsheetMain origin, CaseFrontsheetMain destination) {
        if (origin == null || destination == null) {
            return;
        }
        Field[] fields = destination.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object valueD = field.get(origin);
                Object valueO = field.get(destination);
                if (null == valueO) {
                    field.set(destination, valueD);
                }
                field.setAccessible(false);
            } catch (Exception e) {
                log.error("合并实体类出错", e);
            }
        }
    }

    private ResultVo<List<CodeName>> saveSheet(CaseFrontsheetMain sheet) {
        String bah = sheet.getBah();
        int times = sheet.getAdmissTimes();
        dao.updateAPatientMi(sheet);

        Integer[] addrs = sheet.getStandardAddress();
        if (null != addrs && addrs.length > 0) {
            Integer province = addrs[0];
            Integer city = addrs.length > 1 ? addrs[1] : null;
            Integer district = addrs.length > 2 ? addrs[2] : null;
            dao.updateAddressCascader(bah, province, city, district);
        }

        dao.updateZyActPatient(bah, times, sheet.getAutopsy(), sheet.getDiagConform1(),
                sheet.getDiagConform2(), sheet.getDiagConform3(), sheet.getDiagConform4(),
                sheet.getDiagConform5(), sheet.getHasSurgery(), sheet.getPathologicDiagStr(),
                sheet.getPathologicDiagCode(), sheet.getClinicDiagCode(), sheet.getClinicDiagStr());
        dao.updateZyInActPatient(bah, times, sheet.getAutopsy(), sheet.getDiagConform1(), sheet.getDiagConform2(),
                sheet.getDiagConform3(), sheet.getDiagConform4(), sheet.getDiagConform5(), sheet.getHasSurgery(),
                sheet.getPathologicDiagStr(), sheet.getPathologicDiagCode(), sheet.getClinicDiagCode(), sheet.getClinicDiagStr());
        dao.updateBatjBa1(sheet);
        dao.updateBatjBa2(sheet);
        dao.deleteOldDisdiag(bah, times);
        if (!sheet.getDisdiagList().isEmpty()) {
            List<CaseFrontsheetDisdiag> diags = sheet.getDisdiagList();
            for (int i = 0; i < diags.size(); i++) {
                CaseFrontsheetDisdiag item = diags.get(i);
                if (StringUtil.isBlank(item.getCode())) {
                    break;
                }
                item.setNo(i + 1);
                item.setBah(bah);
                item.setTimes(times);
                dao.writeNewDisdiag(item);
            }
        }
        dao.deleteOldSurgeryRecord(bah, times);
        if (!sheet.getSurgeryList().isEmpty()) {
            List<CaseFrontsheetSurgery> surgeries = sheet.getSurgeryList();
            for (int i = 0; i < surgeries.size(); i++) {
                CaseFrontsheetSurgery item = surgeries.get(i);
                if (StringUtil.isBlank(item.getCode())) {
                    break;
                }
                if (null == item.getDate()) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "手术日期不能为空！");
                }
                item.setNo(i + 1);
                item.setBah(bah);
                item.setTimes(times);
                dao.writeNewZySurgeryRecord(item);
            }
        }
        return ResultVoUtil.success();
    }

    public ResultVo<List<CodeName>> signApply(CaseFrontsheetMain sheet) {
        Integer status = dao.getSignApplyStatus(sheet.getBah(), sheet.getAdmissTimes());
        if (null == status) {
            sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
            List<CodeName> message = VerifyCaseFrontSheet.getInstance().printVerify(sheet);
            if (message.isEmpty()) {
                dao.insertNewSignApply(sheet.getBah(), sheet.getAdmissTimes(),
                        sheet.getName(), sheet.getSex(), TokenUtil.getTokenUserId());
                return ResultVoUtil.success();
            }
            return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", message);
        }
        if (status == 0) {
            return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "此病案已提交过归档申请，请耐心等待病案室签收。");
        }
        return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "此病案已签收，无法继续申请。");
    }

    private ResultVo<List<CodeName>> archiveSheet(CaseFrontsheetMain sheet) {
        String staff = TokenUtil.getTokenUserId();
        List<Integer> roles = userDao.getUserRoles(staff);
        if (roles.contains(7) || roles.contains(1)) {
            String bah = sheet.getBah();
            int times = sheet.getAdmissTimes();
            if (isLateSubmit(sheet.getDismissDate()) > 8) {
                sheet.setLateFlag(1);
            } else {
                sheet.setLateFlag(0);
            }
            //插入数据 SignDate 签收日期  在点击签收后 向数据库中插入
            sheet.setSignDate(new Date());
            sheet.setFileStatus(1);
            //判断是否已经插入过了
            Integer fileStatus = dao.selectFileStatus(sheet.getBah(), sheet.getAdmissTimes());
            if (null != fileStatus && fileStatus == 1) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请勿重复签收 ( ˉ ⌓ ˉ ๑)");
            }
            //在t_case_frontsheet_main表中插入 主体的内容
            dao.insert(sheet);
            //循环插主要的诊断
            for (CaseFrontsheetDisdiag caseFrontsheetDisdiag : sheet.getDisdiagList()) {
                caseFrontsheetDisdiag.setBah(sheet.getBah());
                caseFrontsheetDisdiag.setTimes(sheet.getAdmissTimes());
                if (caseFrontsheetDisdiag.getNo() != null) {
                    createdDao.insert(caseFrontsheetDisdiag);
                }
            }
            //循环插入做过的手术
            for (CaseFrontsheetSurgery caseFrontsheetSurgery : sheet.getSurgeryList()) {
                caseFrontsheetSurgery.setBah(sheet.getBah());
                caseFrontsheetSurgery.setTimes(sheet.getAdmissTimes());
                if (caseFrontsheetSurgery.getNo() != null) {
                    basDao.insert(caseFrontsheetSurgery);
                }
            }
            basDao.updateActFileStatus(bah, times, 1);
            dao.updateSignApply(bah, times, staff);
            return ResultVoUtil.success();
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有签收首页的权限。");
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized ResultVo<String> unArchiveSheet(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        if (sheet.getFileStatus() == 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未签收的病案首页无需解除签收！");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("bah", sheet.getBah());
        map.put("admiss_times", sheet.getAdmissTimes());
        dao.deleteByMap(map);
        map.put("times", map.remove("admiss_times"));
        createdDao.deleteByMap(map);
        basDao.deleteByMap(map);
        log.info("解除签收状态， 操作员：{} >>> 住院号：{}, 住院次数：{}",
                param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes());
        basDao.updateActFileStatus(sheet.getBah(), sheet.getAdmissTimes(), 0);
        dao.writeBaOpLog(param.getOpType(), param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes());
        log.info("写入病案操作日志， 操作员：{} >>> 住院号：{}, 住院次数：{}, 操作编码：{}",
                param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes(), param.getOpType());
        return ResultVoUtil.success("已成功解除签收。");
    }

    private JSONObject qualityControl(CaseFrontsheetMain sheet) {
        JSONObject obj = new JSONObject();
        obj.put("functionId", "100138");
        JSONObject baseinfo = new JSONObject();
        baseinfo.put("name", sheet.getName());
        baseinfo.put("age", sheet.getAge());
        baseinfo.put("sex_id", sheet.getSex());
        Integer agedays = sheet.getAgeDays();
        baseinfo.put("nwb_age", agedays);
        baseinfo.put("out_hosp_id", FilterUtil.filterDismissWay(sheet.getZyDismissWay()));
        baseinfo.put("is_autopsy_id", sheet.getAutopsy());
        JSONObject inputParam = new JSONObject();
        inputParam.put("baseInfo", baseinfo);
        JSONArray hsptzdDagnsInfo = new JSONArray();
        for (CaseFrontsheetDisdiag diag : sheet.getDisdiagList()) {
            if (null == diag.getNo()) {
                break;
            }
            JSONObject itm = new JSONObject();
            itm.put("icd_code", diag.getCode());
            itm.put("dagns_type", diag.getNo() == 1 ? 1 : 2);
            itm.put("disease_name", diag.getName());
            itm.put("order", diag.getNo());
            hsptzdDagnsInfo.add(itm);
        }
        inputParam.put("hsptzdDagnsInfo", hsptzdDagnsInfo);
        JSONArray hsptzdOprtInfo = new JSONArray();
        for (CaseFrontsheetSurgery surgery : sheet.getSurgeryList()) {
            if (null == surgery.getNo()) {
                break;
            }
            JSONObject itm = new JSONObject();
            itm.put("oprt_code", surgery.getCode());
            itm.put("oprt_name", surgery.getName());
            itm.put("oprt_type", surgery.getNo() == 1 ? 1 : 2);
            itm.put("order", surgery.getNo());
            hsptzdOprtInfo.add(itm);
        }
        inputParam.put("hsptzdOprtInfo", hsptzdOprtInfo);
        obj.put("inputParam", inputParam);
        try {
            JSONObject result = srvc.setlQualityControl(obj);
            log.info("病案质控接口：\n参数：{}\n结果：{}", obj, result);
            return result;
        } catch (Exception e) {
            log.error("创智诊断校验访问失败：http://172.16.32.183:8917/mmg-transceiver/interfaceFactory/call");
            return null;
        }
    }

    public ResultVo<Map<String, List<CodeName>>> infoVerification(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        if (sheet.getFileStatus() == 2) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "已最终归档病案首页无法打印！");
        }
        ResultVo<List<CodeName>> save = saveSheet(param.getSheet());
        if (save.getCode() != ExceptionEnum.SUCCESS.getCode()) {
            Map<String, List<CodeName>> map = new HashMap<>();
            map.put("force", save.getData());
            return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", map);
        }
        sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
        sheet.setIsDoctorPrint(true);
        List<CodeName> force = VerifyCaseFrontSheet.getInstance().printVerify(sheet);
        List<CodeName> advice = VerifyCaseFrontSheet.getInstance().adviseVerification(sheet.getSocialNo());
        JSONObject powersi = qualityControl(sheet);
        if (null != powersi) {
            JSONObject responseEntity = powersi.getJSONObject("responseEntity");
            if (null != responseEntity) {
                JSONArray retarr = responseEntity.getJSONArray("newSettleMemInfo");
                if (null != retarr && retarr.size() > 0) {
                    for (int i = 0; i < retarr.size(); i++) {
                        advice.add(new CodeName("", retarr.getJSONObject(i).getString("result_msg")));
                    }
                }
            }
        }
        if (force.isEmpty()) {
            saveSheet(sheet);
            if (advice.isEmpty()) {
                return ResultVoUtil.success();
            }
        }
        Map<String, List<CodeName>> map = new HashMap<>();
        map.put("force", force);
        map.put("advice", advice);
        return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", map);
    }

    public ResultVo<List<CodeName>> saveVerify(OpCaseFrontsheet info) {
        CaseFrontsheetMain sheet = info.getSheet();
        if (sheet.getFileStatus() == 1 && !userDao.getUserRoles(TokenUtil.getTokenUserId()).contains(7)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "已签收的病案首页无法保存，如需保存，请联系病案室对此病案解除签收。");
        }
        if (sheet.getFileStatus() == 2) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "已打印的病案首页无法再次保存！");
        }
        int optype = info.getOpType();
        sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
        List<CodeName> message = optype == 1 ? VerifyCaseFrontSheet.getInstance().saveVerify(sheet) :
                VerifyCaseFrontSheet.getInstance().printVerify(sheet);
        if (message.isEmpty()) {
            final String bah = sheet.getBah();
            final int times = sheet.getAdmissTimes();
            dao.writeBaOpLog(optype, info.getStaffId(), bah, times);
            return optype == 1 ? saveSheet(sheet) : archiveSheet(sheet);
        } else {
            return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", message);
        }
    }

    public ResultVo<List<YiBaoDisdiag>> getYbDiags(String bah, int times) {
        List<YiBaoDisdiag> diags = dao.getYbDiags(bah, times);
        return ResultVoUtil.success(diags);
    }

    @Transactional
    public ResultVo<String> saveYbDiags(SaveYbDiagParam param) {
        dao.deleteOldYbDiag(param.getBah(), param.getTimes());
        List<String> diagCodes = new ArrayList<>();
        for (int i = 0; i < param.getYbDiags().size(); i++) {
            YiBaoDisdiag diag = param.getYbDiags().get(i);
            if (StringUtil.isBlank(diag.getCode())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【诊断序号：" + diag.getNo() + "】诊断编码不能为空！");
            }
            if (StringUtil.isBlank(diag.getName())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【诊断序号：" + diag.getNo() + "】诊断名称不能为空！");
            }
            if (StringUtil.isBlank(diag.getCyzg())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【诊断序号：" + diag.getNo() + "】出院转归不能为空！");
            }
            if (null == diag.getSiDiagType()) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【诊断序号：" + diag.getNo() + "】诊断类别不能为空！");
            }
            if (diagCodes.contains(diag.getCode())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【诊断编码：" + diag.getCode() + "】请勿填入重复的诊断！");
            }
            diagCodes.add(diag.getCode());
            diag.setNo(i + 1);
            diag.setBah(param.getBah());
            diag.setTimes(param.getTimes());
            dao.insertNewYbDiag(diag);
        }
        return ResultVoUtil.success();
    }

    @Transactional(rollbackFor = Exception.class)
    public ResultVo<String> lendOut(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        if (sheet.getFileStatus() == 0) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未签收的病案不可借阅！");
        }
        if (sheet.getLendFlag() == 1) {
            BorrowBase info = dao.getBorrowInfo(sheet.getBah(), sheet.getAdmissTimes());
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "该病案已于：" +
                    DateUtil.formatDatetime(info.getBorrowDate()) + " 借阅给【" + info.getBorrowName() + "】。");
        }
        if (null == sheet.getBorrowDate() || null == sheet.getBorrowId()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "借阅人和借阅时间不可为空！");
        }
        log.info("借阅> 时间：{}，借阅人：{}，操作员：{}，病案号：{}，住院次数：{}",
                sheet.getBorrowDate(), sheet.getBorrowId(), param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes());
        dao.lendZyOut(sheet.getBah(), sheet.getAdmissTimes());
        dao.lendZyInOut(sheet.getBah(), sheet.getAdmissTimes());
        dao.writeLendOutLog(param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes(),
                sheet.getBorrowId(), sheet.getBorrowDate());
        return ResultVoUtil.success();
    }

    @Transactional(rollbackFor = Exception.class)
    public ResultVo<String> lendBack(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        if (sheet.getLendFlag() != 1) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未借阅的病案无需收回！");
        }
        BorrowBase info = dao.getBorrowInfo(sheet.getBah(), sheet.getAdmissTimes());
        dao.lendZyBack(sheet.getBah(), sheet.getAdmissTimes());
        dao.lendZyInBack(sheet.getBah(), sheet.getAdmissTimes());
        dao.writeLendBackLog(param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes(),
                info.getBorrowId(), info.getBorrowDate());
        return ResultVoUtil.success();
    }

    public ResultVo<List<SheetOverview>> advanceSearch(AdvanceSearchParam param) {
        return ResultVoUtil.success(dao.advanceSearch(param));
    }

    public ResultVo<String> fetchSsfz(String code, String bah, Integer times) {
        DisefamilyGrade disefamilyGrade = dao.selectDisefamilyGrade(code);
        if (null == disefamilyGrade) {
            return ResultVoUtil.success("无对照的病种。");
        }
        boolean hasModified = dao.selectModified(bah, times) > 0;
        List<String> surgeries = hasModified ? dao.selectPatientSurgeryCodes(bah, times, "batj_ba4_modify")
                : dao.selectPatientSurgeryCodes(bah, times, "batj_ba4");
        if (ListUtil.isBlank(surgeries)) {
            return ResultVoUtil.success("有对照的非手术分值：" + disefamilyGrade.getNoneOprnGrade());
        }
        List<OprnDisefamilyGrade> oprnGrades = dao.selectOperationDisefamilies(disefamilyGrade.getDisefamilyCode());
        int ssfz = 0;
        for (OprnDisefamilyGrade oprn : oprnGrades) {
            if (surgeries.contains(oprn.getOprnCode())) {
                if (oprn.getOprnGrade() > ssfz) {
                    ssfz = oprn.getOprnGrade();
                }
            }
        }
        if (ssfz != 0) {
            return ResultVoUtil.success("有对照的手术分值：" + ssfz);
        }
        return ResultVoUtil.success("有对照的非手术分值：" + disefamilyGrade.getNoneOprnGrade());
    }

    private int isLateSubmit(Date dismissDate) {
        long days = (System.currentTimeMillis() - dismissDate.getTime()) / 1000 / (3600 * 24);
        return (int) days;
    }

    public void increaseDiagWeight(String code) {
        dao.increaseDiagWeight(code);
    }

    public ResultVo<CodeName> selectSiDiagByBaDiag(String code) {
        CodeName result = dao.selectSiDiagByBaDiag(code);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有查询到此诊断的医保对照诊断。");
        }
        return ResultVoUtil.success(result);
    }

    private StandardAddressMember getStandardAddress(Integer[] addrs) {
        if (null == addrs || addrs.length < 3) {
            return null;
        }
        return dao.selectStandardAddressMember2(addrs[0], addrs[1], addrs[2]);
    }
}
