package thyyxxk.webserver.service.inpatient.casefrontsheet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.BizException;
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.inpatient.casefrontsheet.BasSelectOverviewDao;
import thyyxxk.webserver.dao.his.inpatient.casefrontsheet.CaseFrontSheetDao;
import thyyxxk.webserver.dao.his.inpatient.casefrontsheet.SheetCreatedDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.api.forpowersi.drgdip.frontsheetqualitycheck.QualityCheckParams;
import thyyxxk.webserver.entity.casefrontsheet.*;
import thyyxxk.webserver.entity.casefrontsheet.request.*;
import thyyxxk.webserver.entity.casefrontsheet.request.OpCaseFrontsheet;
import thyyxxk.webserver.entity.casefrontsheet.response.BaOpLog;
import thyyxxk.webserver.entity.casefrontsheet.response.LendOutSheet;
import thyyxxk.webserver.entity.casefrontsheet.state.AuditState;
import thyyxxk.webserver.entity.casefrontsheet.state.State;
import thyyxxk.webserver.entity.covid.Region;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.dictionary.HisWjwMatchEntity;
import thyyxxk.webserver.http.drg.DrgWebApi;
import thyyxxk.webserver.service.externalhttp.PowersiSrvc;
import thyyxxk.webserver.service.zhuyuanyisheng.emr.EmrServer;
import thyyxxk.webserver.utils.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
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;
    private final EmrServer emrService;
    private final DrgWebApi drgWebApi;

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

    public ResultVo<Map<String, List<CodeName>>> getAllDictionary() {
        if (allDictionary.isEmpty()) {
            try {
                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());
            } catch (Exception e) {
                log.error("病案字典提取出错", e);
                allDictionary.clear();
                return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, e.getCause().getMessage());
            }
        }
        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.getInstance().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(DismissedSheetInquiry 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<List<SheetOverview>> basOutPatients(DismissedSheetInquiry param) {
        if (StringUtil.isBlank(param.getStart()) || StringUtil.isBlank(param.getEnd())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "日期范围不能为空。");
        }
        param.setStart(param.getStart() + " 00:00:00");
        param.setEnd(param.getEnd() + " 23:59:59");

        List<SheetOverview> baseList;
        List<SheetOverview> seedList;

        if (StringUtil.notBlank(param.getBah())) {
            baseList = basDao.selectPatientsFromSignedBase(param);
            if (Objects.equals(param.getFileStatus(), State.FileStatus.SIGNED)) {
                if (baseList.isEmpty()) {
                    return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST,
                            "没有找到此患者的已归档病案。");
                }
                if (!Objects.equals(param.getLateFlag(), State.LateFlag.ALL)) {
                    baseList.removeIf(item -> !Objects.equals(item.getLateFlag(), param.getLateFlag()));
                }
                return ResultVoUtil.success(baseList);
            }

            seedList = basDao.selectPatientsForBasByBah(param);
            baseList = removeDuplicateData(baseList, seedList);
            if (baseList.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST,
                        "没有找到此患者的未归档病案。");
            }
            if (!Objects.equals(param.getLateFlag(), State.LateFlag.ALL)) {
                baseList.removeIf(item -> !Objects.equals(item.getLateFlag(), param.getLateFlag()));
            }
            return ResultVoUtil.success(baseList);
        }
        if (StringUtil.notBlank(param.getWard())) {
            baseList = basDao.selectPatientsForBasByWard2(param);
            if (param.getFileStatus() == State.FileStatus.UNSIGNED) {
                seedList = basDao.selectPatientsForBasByWard(param);
                baseList = removeDuplicateData(baseList, seedList);
            }
            if (!Objects.equals(param.getLateFlag(), State.LateFlag.ALL)) {
                baseList.removeIf(item -> !Objects.equals(item.getLateFlag(), param.getLateFlag()));
            }
            return ResultVoUtil.success(baseList);
        }
        baseList = basDao.selectPatientsForBasByFileStatus2(param);
        if (param.getFileStatus() == State.FileStatus.UNSIGNED) {
            seedList = basDao.selectPatientsForBasByFileStatus(param);
            baseList = removeDuplicateData(baseList, seedList);
        }
        if (!Objects.equals(param.getLateFlag(), State.LateFlag.ALL)) {
            baseList.removeIf(item -> !Objects.equals(item.getLateFlag(), param.getLateFlag()));
        }
        return ResultVoUtil.success(baseList);
    }

    private List<SheetOverview> removeDuplicateData(List<SheetOverview> baseList,
                                                    List<SheetOverview> seedList) {
        if (baseList.isEmpty()) {
            return seedList;
        }
        if (seedList.isEmpty()) {
            return baseList;
        }
        List<String> keys = new ArrayList<>();
        for (SheetOverview overview : baseList) {
            String key = overview.getBah().trim() + "-" + overview.getTimes();
            keys.add(key);
        }
        seedList.removeIf(item -> keys.contains(item.getBah().trim() + "-" + item.getTimes()));
        baseList.addAll(seedList);
        return baseList;
    }

    public CaseFrontsheetMain getPatientInfo(SheetOverview overview) {
        String bah = overview.getBah();
        Integer times = overview.getTimes();
        StandardAddressMember standardAddressMember = getStandardAddressMember(bah);
        CaseFrontsheetMain sheet = dao.selectStoredSheetMain(bah, times);
        if (null != sheet) {
            sheet.setDisdiagList(getSheetDisDiags(bah, times, State.FileStatus.SIGNED));
            sheet.setSurgeryList(getSheetSurgeries(bah, times, State.FileStatus.SIGNED));
            sheet.setSupplement(getSheetSupplement(bah, times));
            if (null != standardAddressMember) {
                sheet.setStandardAddress(standardAddressMember.makeStandardAddress());
                sheet.setLivePlaceCombo(standardAddressMember.makeAddressCombo() + sheet.getLivePlace());
            }
            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());
                }
            }
            if (null == sheet.getDismissDate()) {
                Date dismissDate = dao.getDismissDateFromYzActOrder("yz_act_order", bah, times);
                if (null == dismissDate) {
                    dismissDate = dao.getDismissDateFromYzActOrder("yz_inact_order", bah, times);
                }
                sheet.setDismissDate(dismissDate);
                Integer days = DateUtil.daysBetween(dismissDate, sheet.getAdmissDate());
                sheet.setAdmissDays(0 == days ? "1" : String.valueOf(days));
            }
            if (StringUtil.isBlank(sheet.getAdmissDays()) || sheet.getAdmissDays().equals("-1")) {
                Integer days = DateUtil.daysBetween(sheet.getDismissDate(), sheet.getAdmissDate());
                sheet.setAdmissDays(0 == days ? "1" : String.valueOf(days));
            }
            autoFillPart(sheet);
            return sheet;
        }
        int inHospital = overview.getInOutFlag();
        if (inHospital == State.InHospital.NO) {
            if (dao.selectActCount(bah, times) > 0) {
                inHospital = State.InHospital.YES;
            }
        }
        sheet = dao.getAPatientMi(bah);
        if (null == sheet) {
            return null;
        }
        CaseFrontsheetMain sheet1 = inHospital == State.InHospital.YES ?
                dao.getZyActPatient("zy_actpatient", "yz_act_order", bah, times) :
                dao.getZyActPatient("zy_inactpatient", "yz_inact_order", bah, times);
        if (null == sheet1) {
            sheet1 = inHospital == State.InHospital.YES ?
                    dao.getZyActPatient("zy_inactpatient", "yz_inact_order", bah, times) :
                    dao.getZyActPatient("zy_actpatient", "yz_act_order", bah, times);
        }
        sheet.setAge(DateUtil.calculateAge(sheet.getBirthDate(), sheet1.getAdmissDate()));
        if (null != sheet.getAge() && sheet.getAge() == 0) {
            sheet.setAgeDays(DateUtil.calculateNewBornAge(sheet.getBirthDate(), sheet1.getAdmissDate()));
        }
        if (StringUtil.isBlank(sheet1.getMedType())) {
            String injurySerialNo = dao.selectInjurySerialNo(bah, times);
            if (StringUtil.notBlank(injurySerialNo)) {
                sheet1.setMedType("42");
            }
        }
        sheet1.setMedTypeName(MedType.getName(sheet1.getMedType()));
        sheet1.setInsutype(Insutype.getName(sheet1.getInsutype()));
        final int hasInfant = dao.getInfant(bah, times);
        sheet1.setHasInfant(String.valueOf(hasInfant));
        if (null == sheet1.getDismissDate()) {
            final Date dismissDate = inHospital == State.InHospital.YES ?
                    dao.getDismissDateFromYzActOrder("yz_inact_order", bah, times)
                    : dao.getDismissDateFromYzActOrder("yz_act_order", bah, times);
            sheet1.setDismissDate(dismissDate);
        }
        CaseFrontsheetMain sheet2 = dao.getBatjBa1(bah, times);
        if (sheet2 == null && dao.isBatjBa1Exist(bah, times) == 0) {
            dao.createBatjBa1(bah, times, sheet.getName(), sheet1.getAdmissDate(),
                    sheet1.getAdmissDept(), sheet1.getAdmissWard());
            log.info("insert batjBa1>>> " + bah + ", " + times);
        }
        CaseFrontsheetMain sheet3 = inHospital == 1 ? dao.getBatjBa2ForInPatient(bah, times) :
                dao.getBatjBa2ForOutPatient(bah, times);
        if (sheet3 == null && dao.isBatjBa2Exist(bah, times) == 0) {
            dao.createBatjBa2(bah, times);
            log.info("insert batjBa2>>> " + bah + ", " + times);
        }
        FrontSheetUtil.mergeObject(sheet1, sheet);
        FrontSheetUtil.mergeObject(sheet2, sheet);
        FrontSheetUtil.mergeObject(sheet3, sheet);
        Integer days = DateUtil.daysBetween(sheet.getDismissDate(), sheet.getAdmissDate());
        sheet.setAdmissDays(0 == days ? "1" : String.valueOf(days));
        if (null == sheet.getQualityControlDate()) {
            sheet.setQualityControlDate(new Date());
        }
        sheet.setDisdiagList(getSheetDisDiags(bah, times, State.FileStatus.UNSIGNED));
        sheet.setSurgeryList(getSheetSurgeries(bah, times, State.FileStatus.UNSIGNED));
        sheet.setSupplement(getSheetSupplement(bah, times));
        if (null == standardAddressMember) {
            sheet.setLivePlaceCombo(sheet.getLivePlace());
        } else {
            sheet.setStandardAddress(standardAddressMember.makeStandardAddress());
            sheet.setLivePlaceCombo(standardAddressMember.makeAddressCombo() + sheet.getLivePlace());
        }
        List<CodeName> patCharges = dao.selectPatCharges(bah, times);
        for (CodeName item : patCharges) {
            String code = String.valueOf(item.getCode().charAt(0)).toUpperCase() +
                          item.getCode().substring(1);
            try {
                Method m = sheet.getClass().getMethod("set" + code, String.class);
                m.invoke(sheet, item.getName());
            } catch (Exception e) {
                log.error("反射出错", e);
            }
        }
        sheet.setSurgicalFee(DecimalUtil.add(sheet.getAnesthetizeFee(), sheet.getSurgeryFee()));
        autoFillPart(sheet);
        return sheet;
    }

    private void autoFillPart(CaseFrontsheetMain sheet) {
        String patNo = sheet.getBah();
        int times = sheet.getAdmissTimes();
        if (StringUtil.isBlank(sheet.getCaseClassification())) {
            String blfxElement = dao.selectBlfxElement(patNo, times);
            if (StringUtil.notBlank(blfxElement)) {
                JSONObject blfxObj = JSONObject.parseObject(blfxElement);
                JSONArray blfxArray = blfxObj.getJSONArray("病例分型");
                if (null != blfxArray && !blfxArray.isEmpty()) {
                    JSONObject blfxItem = blfxArray.getJSONObject(0);
                    sheet.setCaseClassification(blfxItem.getString("code"));
                }
            }
        }
        if (StringUtil.isBlank(sheet.getBacilliculture())) {
            int bacillicultureCount = dao.selectBacillicultureCount(patNo, times);
            sheet.setBacilliculture(bacillicultureCount > 0 ? "1" : "2");
        }
        if (StringUtil.isBlank(sheet.getStatutoryEpidemic())) {
            List<Map<String, String>> epidemics = dao.selectStatutoryEpidemic(patNo, times);
            if (ListUtil.notBlank(epidemics)) {
                Map<String, String> epidemic = epidemics.get(0);
                if (null != epidemic) {
                    if (StringUtil.notBlank(epidemic.get("a"))) {
                        sheet.setStatutoryEpidemic("1");
                    } else if (StringUtil.notBlank(epidemic.get("b"))) {
                        sheet.setStatutoryEpidemic("2");
                    } else if (StringUtil.notBlank(epidemic.get("c"))) {
                        sheet.setStatutoryEpidemic("3");
                    }
                }
            }
        }
        if (StringUtil.isBlank(sheet.getUseAntibiotic())) {
            int antibioticCounts = dao.selectAntibiotics(patNo, times);
            sheet.setUseAntibiotic(antibioticCounts > 0 ? "1" : "2");
        }

        AuditState auditState = dao.selectStates(patNo, times);
        if (null == auditState) {
            auditState = AuditState.NONE;
        }
        sheet.setAuditState(auditState);

        if (null == sheet.getSupplement().getHadEcmo()) {
            sheet.getSupplement().setHadEcmo(2);
        }
        if (null == sheet.getSupplement().getInfusion()) {
            sheet.getSupplement().setInfusion(1);
        }
    }

    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 FrontSheetSupplement getSheetSupplement(String bah, int times) {
        FrontSheetSupplement result = dao.getSheetSupplement(bah, times);
        if (null == result) {
            dao.createSheetSupplement(bah, times);
            result = new FrontSheetSupplement();
            result.setBah(bah);
            result.setTimes(times);
        }
        fillSeparatedTime(result);
        if (StringUtil.notBlank(result.getAdmDiagCode()) && StringUtil.notBlank(result.getAdmDiagName())) {
            return result;
        }
        JSONArray diagList;
        JSONObject emrPatientData = emrService.getEmrPatientData(bah, times);
        try {
            diagList = emrPatientData.getJSONArray("入院诊断");
        } catch (Exception e) {
            diagList = null;
        }
        if (null == diagList || diagList.isEmpty()) {
            return result;
        }
        JSONObject diagItem = diagList.getJSONObject(0);
        result.setAdmDiagCode(diagItem.getString("code"));
        result.setAdmDiagName(diagItem.getString("name"));
        return result;
    }

    private void fillSeparatedTime(FrontSheetSupplement supplement) {
        if (null != supplement.getDiagnosisConfirmDate()) {
            Integer[] datetimeArr = getSplitDatetime(supplement.getDiagnosisConfirmDate());
            supplement.setDiagnosisConfirmYear(datetimeArr[0]);
            supplement.setDiagnosisConfirmMonth(datetimeArr[1]);
            supplement.setDiagnosisConfirmDay(datetimeArr[2]);
        }
        if (null != supplement.getStartIcuTime()) {
            Integer[] datetimeArr = getSplitDatetime(supplement.getStartIcuTime());
            supplement.setStartIcuYear(datetimeArr[0]);
            supplement.setStartIcuMonth(datetimeArr[1]);
            supplement.setStartIcuDay(datetimeArr[2]);
            supplement.setStartIcuHour(datetimeArr[3]);
            supplement.setStartIcuMinute(datetimeArr[4]);
        }
        if (null != supplement.getEndIcuTime()) {
            Integer[] datetimeArr = getSplitDatetime(supplement.getEndIcuTime());
            supplement.setEndIcuYear(datetimeArr[0]);
            supplement.setEndIcuMonth(datetimeArr[1]);
            supplement.setEndIcuDay(datetimeArr[2]);
            supplement.setEndIcuHour(datetimeArr[3]);
            supplement.setEndIcuMinute(datetimeArr[4]);
        }
        if (null != supplement.getStartEcmoTime()) {
            Integer[] datetimeArr = getSplitDatetime(supplement.getStartEcmoTime());
            supplement.setStartEcmoYear(datetimeArr[0]);
            supplement.setStartEcmoMonth(datetimeArr[1]);
            supplement.setStartEcmoDay(datetimeArr[2]);
            supplement.setStartEcmoHour(datetimeArr[3]);
            supplement.setStartEcmoMinute(datetimeArr[4]);
        }
        if (null != supplement.getEndEcmoTime()) {
            Integer[] datetimeArr = getSplitDatetime(supplement.getEndEcmoTime());
            supplement.setEndEcmoYear(datetimeArr[0]);
            supplement.setEndEcmoMonth(datetimeArr[1]);
            supplement.setEndEcmoDay(datetimeArr[2]);
            supplement.setEndEcmoHour(datetimeArr[3]);
            supplement.setEndEcmoMinute(datetimeArr[4]);
        }
    }

    private Integer[] getSplitDatetime(Date date) {
        String formatted = DateUtil.formatDatetime(date);
        String[] dateTime = formatted.split(" ");
        String[] dateArr = dateTime[0].split("-");
        String[] timeArr = dateTime[1].split(":");
        return new Integer[]{
                Integer.parseInt(dateArr[0]),
                Integer.parseInt(dateArr[1]),
                Integer.parseInt(dateArr[2]),
                Integer.parseInt(timeArr[0]),
                Integer.parseInt(timeArr[1])
        };
    }

    private void combineSeparatedTime(FrontSheetSupplement s) {
        Date diagConfirmDate = makeDateBySplitTime(s.getDiagnosisConfirmYear(),
                s.getDiagnosisConfirmMonth(), s.getDiagnosisConfirmDay(),
                null, null, "入院后确认日期。");
        if (null != diagConfirmDate) {
            s.setDiagnosisConfirmDate(diagConfirmDate);
        }

        Date startIcuTime = makeDateBySplitTime(s.getStartIcuYear(), s.getStartIcuMonth(),
                s.getStartIcuDay(), s.getStartIcuHour(), s.getStartIcuMinute(), "进入重症监护室时间。");
        s.setStartIcuTime(startIcuTime);

        Date endIcuTime = makeDateBySplitTime(s.getEndIcuYear(), s.getEndIcuMonth(),
                s.getEndIcuDay(), s.getEndIcuHour(), s.getEndIcuMinute(), "转出重症监护室时间。");
        s.setEndIcuTime(endIcuTime);

        Date startEcmoTime = makeDateBySplitTime(s.getStartEcmoYear(), s.getStartEcmoMonth(),
                s.getStartEcmoDay(), s.getStartEcmoHour(), s.getStartEcmoMinute(), "ECMO上机时间。");
        s.setStartEcmoTime(startEcmoTime);

        Date endEcmoTime = makeDateBySplitTime(s.getEndEcmoYear(), s.getEndEcmoMonth(),
                s.getEndEcmoDay(), s.getEndEcmoHour(), s.getEndEcmoMinute(), "ECMO撤机时间。");
        s.setEndEcmoTime(endEcmoTime);
    }

    private Date makeDateBySplitTime(Integer year, Integer month, Integer day,
                                     Integer hour, Integer minute, String tip) {
        if (null == year || null == month || null == day) {
            return null;
        }
        if (year > 9999 || year < 1 || month > 12 || month < 1 || day > 31 || day < 1) {
            throw new BizException(ExceptionEnum.INTERNAL_SERVER_ERROR, "请填写正确的 " + tip);
        }
        Calendar calendar = Calendar.getInstance();
        if (null == hour || null == minute) {
            calendar.set(year, month - 1, day);
            return calendar.getTime();
        }
        if (hour > 23 || hour < 0 || minute > 59 || minute < 0) {
            throw new BizException(ExceptionEnum.INTERNAL_SERVER_ERROR, "请填写正确的 " + tip);
        }
        calendar.set(year, month - 1, day, hour, minute);
        return calendar.getTime();
    }

    private List<CaseFrontsheetDisdiag> getSheetDisDiags(String bah, int times, int status) {
        List<CaseFrontsheetDisdiag> disdiags = status == State.FileStatus.SIGNED ?
                dao.selectSignedSheetDiags(bah, times) : dao.getDisdiags(bah, times);
        if (disdiags.isEmpty()) {
            JSONObject emrPatientData = emrService.getEmrPatientData(bah, times);
            JSONArray diagList;
            try {
                diagList = emrPatientData.getJSONArray("出院诊断");
            } catch (Exception e) {
                diagList = null;
            }
            if (null != diagList) {
                for (int i = 0; i < diagList.size(); i++) {
                    JSONObject diagItem = diagList.getJSONObject(i);
                    CaseFrontsheetDisdiag diag = dao.selectDiagInfoByCode(diagItem.getString("code"));
                    if (null != diag) {
                        diag.setNo(disdiags.size() + 1);
                        disdiags.add(diag);
                    }
                }
            }
        }
        while (disdiags.size() < 27) {
            disdiags.add(new CaseFrontsheetDisdiag());
        }
        return disdiags;
    }

    private List<CaseFrontsheetSurgery> getSheetSurgeries(String bah, int times, int status) {
        List<CaseFrontsheetSurgery> surgeries = status == State.FileStatus.SIGNED ?
                dao.selectSignedSheetSurgeries(bah, times) : dao.getSurgeries(bah, times);
        if (surgeries.isEmpty()) {
            JSONArray oprtList = emrService.getPatientSurgery(bah, times);
            for (int i = 0; i < oprtList.size(); i++) {
                JSONObject oprtItem = oprtList.getJSONObject(i);
                JSONObject oprtName;
                try {
                    oprtName = oprtItem.getJSONObject("已行手术");
                } catch (Exception e) {
                    continue;
                }
                if (null == oprtName) {
                    continue;
                }
                JSONArray oprtNameVals = oprtName.getJSONArray("value");
                if (null == oprtNameVals) {
                    continue;
                }
                String opdate = oprtItem.getJSONObject("手术日期").getString("value");
                JSONArray oprtorArr = oprtItem.getJSONObject("术者").getJSONArray("value");
                JSONObject oprtor = null == oprtorArr ? new JSONObject() : oprtorArr.getJSONObject(0);

                JSONObject assis1 = new JSONObject();
                JSONObject firstAssist = oprtItem.getJSONObject("第一助手");
                if (null != firstAssist) {
                    JSONArray assis1Arr = firstAssist.getJSONArray("value");
                    assis1 = null == assis1Arr ? assis1 : assis1Arr.getJSONObject(0);
                }

                JSONObject assis2 = new JSONObject();
                JSONObject secondAssist = oprtItem.getJSONObject("第二助手");
                if (null != secondAssist) {
                    JSONArray assis2Arr = secondAssist.getJSONArray("value");
                    assis2 = null == assis2Arr ? assis2 : assis2Arr.getJSONObject(0);
                }

                JSONObject anstor = new JSONObject();
                JSONObject anesDor = oprtItem.getJSONObject("麻醉医生");
                if (null != anesDor) {
                    JSONArray anstorArr = anesDor.getJSONArray("value");
                    anstor = null == anstorArr ? anstor : anstorArr.getJSONObject(0);
                }

                for (int j = 0; j < oprtNameVals.size(); j++) {
                    JSONObject oprtCodeName = oprtNameVals.getJSONObject(j);
                    CaseFrontsheetSurgery surgery = dao.selectSurgeryByCode(oprtCodeName.getString("code"));
                    if (null != surgery) {
                        surgery.setNo(surgeries.size() + 1);
                        surgery.setDate(DateUtil.parse(opdate));
                        surgery.setOperator(oprtor.getString("code"));
                        surgery.setOperatorName(oprtor.getString("name"));
                        surgery.setAssistantOne(assis1.getString("code"));
                        surgery.setAssistantOneName(assis1.getString("name"));
                        surgery.setAssistantTwo(assis2.getString("code"));
                        surgery.setAssistantTwoName(assis2.getString("name"));
                        surgery.setAnaesthesiaor(anstor.getString("code"));
                        surgery.setAnaesthesiaorName(anstor.getString("name"));
                        surgeries.add(surgery);
                    }
                }
            }
        }
        while (surgeries.size() < 5) {
            surgeries.add(new CaseFrontsheetSurgery());
        }
        return surgeries;
    }

    private ResultVo<List<CodeName>> saveSheet(CaseFrontsheetMain sheet, String staffId) {
        String bah = sheet.getBah();
        int times = sheet.getAdmissTimes();
        if (StringUtil.notBlank(sheet.getSocialNo())) {
            sheet.setSocialNo(sheet.getSocialNo().toUpperCase());
        }
        combineSeparatedTime(sheet.getSupplement());
        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);
        log.info("{}", sheet.getSupplement());
        dao.updateSheetSupplement(sheet.getSupplement());
        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);
                item.setCut(FilterUtil.filterCut(item.getCutHeal()));
                item.setHeal(FilterUtil.filterHeal(item.getCutHeal()));
                dao.writeNewZySurgeryRecord(item);
            }
        }
        if (null != staffId) {
            dao.writeBaOpLog(1, staffId, bah, times);
        }
        return ResultVoUtil.success();
    }

    private ResultVo<List<CodeName>> archiveSheet(CaseFrontsheetMain sheet, String staffId) {
        String staff = TokenUtil.getInstance().getTokenUserId();
        List<Integer> roles = userDao.getUserRoles(staff);
        if (!roles.contains(7) && !roles.contains(1)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您没有签收首页的权限。");
        }
        String bah = sheet.getBah();
        int times = sheet.getAdmissTimes();

        Date firstSignDate = dao.selectFirstSignDate(bah, times);
        sheet.setSignDate(null == firstSignDate ? new Date() : firstSignDate);
        sheet.setUnsignDate(null);
        sheet.setSignStaff(staff);
        sheet.setFileStatus(State.FileStatus.SIGNED);
        //判断是否已经签收过了
        Integer fileStatus = dao.selectFileStatus(sheet.getBah(), sheet.getAdmissTimes());
        if (!Objects.equals(fileStatus, State.FileStatus.SIGNED)) {
            if (null == sheet.getLateFlag()) {
                sheet.setLateFlag(calculateLateState(sheet.getDismissDate()));
            }
            fillMajorErrorFlags(sheet);
            insertSheetData(sheet);
            basDao.updateActFileStatus(bah, times, State.FileStatus.SIGNED);
            dao.writeBaOpLog(2, staffId, bah, times);
            return ResultVoUtil.success();
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请勿重复签收。");
    }

    private void fillMajorErrorFlags(CaseFrontsheetMain sheet) {
        List<String> majorErrors = basDao.getMajorErrors(sheet.getBah(), sheet.getAdmissTimes());
        if (majorErrors.isEmpty()) {
            return;
        }
        for (String majorError : majorErrors) {
            if (majorError.contains("主要诊断填写错误")) {
                sheet.setMaindiagInputErr(1);
            }
            if (majorError.contains("主要诊断编码错误")) {
                sheet.setMaindiagCodeErr(1);
            }
            if (majorError.contains("主要手术填写错误")) {
                sheet.setMainsurgInputErr(1);
            }
            if (majorError.contains("主要手术编码错误")) {
                sheet.setMainsurgCodeErr(1);
            }
        }
    }

    public void insertSheetData(CaseFrontsheetMain sheet) {
        if (null == sheet.getSignStaff()) {
            sheet.setSignStaff(dao.selectSignStaff(sheet.getBah(), sheet.getAdmissTimes()));
        }
        if (StringUtil.notBlank(sheet.getBirthPlace()) &&
                StringUtil.isBlank(sheet.getBirthPlaceName())) {
            String bpName = dao.getDistrictName(sheet.getBirthPlace());
            if (StringUtil.isBlank(bpName)) {
                bpName = sheet.getBirthPlace();
            }
            sheet.setBirthPlaceName(bpName);
        }
        dao.deleteOldSheet(sheet.getBah(), sheet.getAdmissTimes());
        //在t_case_frontsheet_main表中插入 主体的内容
        dao.insert(sheet);
        //循环插主要的诊断
        QueryWrapper<CaseFrontsheetDisdiag> diagWrapper = new QueryWrapper<>();
        diagWrapper.eq("bah", sheet.getBah());
        diagWrapper.eq("times", sheet.getAdmissTimes());
        createdDao.delete(diagWrapper);
        for (CaseFrontsheetDisdiag caseFrontsheetDisdiag : sheet.getDisdiagList()) {
            caseFrontsheetDisdiag.setBah(sheet.getBah());
            caseFrontsheetDisdiag.setTimes(sheet.getAdmissTimes());
            if (caseFrontsheetDisdiag.getNo() != null) {
                createdDao.insert(caseFrontsheetDisdiag);
            }
        }
        //循环插入做过的手术
        QueryWrapper<CaseFrontsheetSurgery> surgeryWrapper = new QueryWrapper<>();
        surgeryWrapper.eq("bah", sheet.getBah());
        surgeryWrapper.eq("times", sheet.getAdmissTimes());
        basDao.delete(surgeryWrapper);
        for (CaseFrontsheetSurgery caseFrontsheetSurgery : sheet.getSurgeryList()) {
            caseFrontsheetSurgery.setBah(sheet.getBah());
            caseFrontsheetSurgery.setTimes(sheet.getAdmissTimes());
            if (caseFrontsheetSurgery.getNo() != null) {
                basDao.insert(caseFrontsheetSurgery);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized ResultVo<String> unArchiveSheet(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        if (sheet.getFileStatus() == State.FileStatus.UNSIGNED) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未签收的病案首页无需解除签收！");
        }
        dao.updateSignStateToUnsigned(sheet.getBah(), sheet.getAdmissTimes());
        log.info("解除签收状态， 操作员：{} >>> 住院号：{}, 住院次数：{}",
                param.getStaffId(), sheet.getBah(), sheet.getAdmissTimes());
        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 powersiQualityCheck(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参数：{}\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>>> printVerification(OpCaseFrontsheet param) {
        CaseFrontsheetMain sheet = param.getSheet();
        Integer status = dao.selectFileStatus(sheet.getBah(), sheet.getAdmissTimes());
        if (null != status && status == State.FileStatus.SIGNED) {
            List<Integer> roles = dao.getUserRoles(param.getStaffId());
            if (roles.contains(60)) {
                return ResultVoUtil.success();
            }
            if (!roles.contains(7)) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "已最终归档病案首页无法进行此操作！");
            }
        }
        sheet.setIsDoctorPrint(true);
        sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
        ResultVo<List<CodeName>> save = saveSheet(sheet, TokenUtil.getInstance().getTokenUserId());
        if (!Objects.equals(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);
        }

        Map<String, List<CodeName>> warnings = beginAnalyzeSheet(sheet);
        if (warnings.get("force").isEmpty()) {
            if (warnings.get("advice").isEmpty()) {
                return ResultVoUtil.success();
            }
        }
        return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", warnings);
    }

    public ResultVo<List<CodeName>> saveVerify(OpCaseFrontsheet info) {
        CaseFrontsheetMain sheet = info.getSheet();
        Integer status = dao.selectFileStatus(sheet.getBah(), sheet.getAdmissTimes());
        if (null != status && status == State.FileStatus.SIGNED) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "已签收的病案首页无法保存，如需保存，请联系病案室对此病案解除签收。");
        }
        sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
        sheet.getSurgeryList().forEach(item -> {
            if (StringUtil.notBlank(item.getCode())) {
                item.setType(dao.selectOperationType(item.getCode()));
            }
        });
        if (info.getOpType() == 2) {
            return archiveSheet(sheet, info.getStaffId());
        }
        List<CodeName> message = VerifyCaseFrontSheet.getInstance().saveVerify(sheet);
        if (message.isEmpty()) {
            if (!sheet.getDisdiagList().isEmpty()) {
                sheet.setMainDisdiagStatus(sheet.getDisdiagList().get(0).getDismissStatus());
            }
            return saveSheet(sheet, info.getStaffId());
        }
        return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "校验未通过。", message);
    }

    private Map<String, List<CodeName>> beginAnalyzeSheet(CaseFrontsheetMain sheet) {
        sheet.getSurgeryList().forEach(item -> {
            if (StringUtil.notBlank(item.getCode())) {
                item.setType(dao.selectOperationType(item.getCode()));
            }
        });
        List<CodeName> force = VerifyCaseFrontSheet.getInstance().printVerify(sheet);
        CaseFrontsheetDisdiag disdiag = sheet.getDisdiagList().get(0);
        List<CodeName> advice = VerifyCaseFrontSheet
                .getInstance()
                .adviseVerification(sheet.getSocialNo(), sheet.getBirthDate(), disdiag.getCode() , sheet.getAge() , sheet.getMarriage());
        setlQualityControlPass(sheet, advice);
        surgeryChargesVerify(sheet, advice);
        JSONObject powersi = powersiQualityCheck(sheet);
        if (null != powersi) {
            JSONObject responseEntity = powersi.getJSONObject("responseEntity");
            if (null != responseEntity) {
                JSONArray retarr = responseEntity.getJSONArray("newSettleMemInfo");
                if (null != retarr && !retarr.isEmpty()) {
                    for (int i = 0; i < retarr.size(); i++) {
                        advice.add(new CodeName("", retarr.getJSONObject(i).getString("result_msg")));
                    }
                }
            }
        }
        Map<String, List<CodeName>> map = new HashMap<>();
        map.put("force", force);
        map.put("advice", advice);
        return map;
    }

    public ResultVo<Map<String, List<CodeName>>> sheetVerification(SheetOverview view) {
        if (StringUtil.isBlank(view.getBah()) || null == view.getTimes() || null == view.getInOutFlag()) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "住院号、住院次数、在院状态不能为空。");
        }
        CaseFrontsheetMain sheet = getPatientInfo(view);
        if (null == sheet) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有查询到病案数据。");
        }
        Map<String, List<CodeName>> warnings = beginAnalyzeSheet(sheet);
        List<CodeName> forces = warnings.get("force");
        if (view.getInOutFlag() == 1) {
            forces.removeIf(item -> Objects.equals(item.getCode(), "dismissDate"));
            forces.removeIf(item -> Objects.equals(item.getCode(), "pathologicDiagCode"));
        }
        return ResultVoUtil.success(warnings);
    }

    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(SaveYbDiag 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();
    }

    public ResultVo<List<SheetOverview>> advanceSearch(AdvanceSearch 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 Integer calculateLateState(Date dismissDate) {
        long days = (System.currentTimeMillis() - dismissDate.getTime()) / 1000 / (3600 * 24);
        return (int) days > 6 ? State.LateFlag.LATE : State.LateFlag.NOT_LATE;
    }

    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]);
    }

    private void setlQualityControlPass(CaseFrontsheetMain sheet, List<CodeName> messages) {
        String patNo = sheet.getBah();
        int times = sheet.getAdmissTimes();
        String admdvs = dao.selectSetlInsuplcAdmdvs(patNo, times);
        if (StringUtil.notBlank(admdvs) && admdvs.startsWith("43")) {
            Integer qualityPassed = dao.qualityPass(patNo, times);
            if (null == qualityPassed || qualityPassed != 1) {
                messages.add(new CodeName("", "此患者医保结算清单质控未通过！"));
            }
        }
    }

    private void surgeryChargesVerify(CaseFrontsheetMain sheet, List<CodeName> messages) {
        List<CaseFrontsheetSurgery> surgeries = sheet.getSurgeryList();
        if (null != surgeries && !surgeries.isEmpty()) {
            List<HisWjwMatchEntity> surgeryChargeCode = dao.selectSurgeryChargeCode(surgeries);
            for (HisWjwMatchEntity entity : surgeryChargeCode) {
                if (StringUtil.notBlank(entity.getWjwCode())) {
                    entity.setChargeCode(entity.getWjwCode().split("\\^"));
                    entity.setChargeName(entity.getWjwName().split("\\^"));
                    Integer chargeSumamt = dao.selectChargeSumamt(sheet.getBah(), sheet.getAdmissTimes(), entity.getChargeCode());
                    if (null == chargeSumamt || chargeSumamt < 1) {
                        String charges = entity.getWjwName().replaceAll("\\^", "，");
                        messages.add(new CodeName("surgeryTable", "患者有手术【" + entity.getName() +
                                                                  "】，但没有找到对应的收费项目【" + charges + "】。"));
                    }
                }
            }
        }
    }

    public ResultVo<String> frontsheetQualityCheck(CaseFrontsheetMain sheet) {
        List<CodeName> anstWays = dao.selectZdAnstWays();
        Map<String, CodeName> anstWaysMap = new HashMap<>();
        for (CodeName item : anstWays) {
            anstWaysMap.put(item.getCode(), item);
        }

        List<CodeName> countries = dao.selectZdCountries();
        Map<String, CodeName> countriesMap = new HashMap<>();
        for (CodeName item : countries) {
            countriesMap.put(item.getCode(), item);
        }

        List<CodeName> nations = dao.selectZdNations();
        Map<String, CodeName> nationsMap = new HashMap<>();
        for (CodeName item : nations) {
            nationsMap.put(item.getCode(), item);
        }

        QualityCheckParams params = new QualityCheckParams();
        params.setBaseInfo(FrontSheetUtil.fillBaseInfoFromSheet(sheet, countriesMap, nationsMap));
        params.setDiseInfoList(FrontSheetUtil.fillDiseInfoFromSheet(sheet.getDisdiagList()));
        params.setOprtInfoList(FrontSheetUtil.fillOprtInfoFromSheet(sheet.getSurgeryList(), anstWaysMap));
        JSONObject jsonParams = JSONObject.parseObject(JSON.toJSONString(params, SerializerFeature.WriteNullStringAsEmpty));
        return drgWebApi.frontsheetQualityCheck(jsonParams);
    }

    public ResultVo<String> isMedinsSetl(String patNo, Integer times) {
        String admdvs = dao.selectSetlInsuplcAdmdvs(patNo, times);
        if (StringUtil.isBlank(admdvs)) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "自费及工伤患者无需进行医保结算单质控。");
        }
        if (!admdvs.startsWith("43")) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "跨省异地患者无需进行医保结算单质控。");
        }
        return ResultVoUtil.success();
    }

    public String markDuplicate(MarkStateRequest request) {
        Integer fileStatus = dao.selectFileStatus(request.getBah(), request.getTimes());
        if (null == fileStatus || fileStatus == State.FileStatus.UNSIGNED) {
            return "未签收的病案不可标记复印。";
        }
        if (StringUtil.isBlank(request.getVisitStaff())) {
            return "请填写来访人员。";
        }
        request.setOpStaff(TokenUtil.getInstance().getTokenUserId());
        int insert = dao.executeDuplicate(request);
        if (insert == 0) {
            return "操作失败，无法向数据库插入记录。";
        }
        return "OK";
    }

    public String markClosedown(MarkStateRequest request) {
        Integer fileStatus = dao.selectFileStatus(request.getBah(), request.getTimes());
        if (null == fileStatus || fileStatus == State.FileStatus.UNSIGNED) {
            return "未签收的病案不可标记封存。";
        }
        if (StringUtil.isBlank(request.getVisitStaff())) {
            return "请填写来访人员。";
        }
        request.setOpStaff(TokenUtil.getInstance().getTokenUserId());
        int insert = dao.executeClosedown(request);
        if (insert == 0) {
            return "操作失败，无法向数据库插入记录。";
        }
        return "OK";
    }

    public MarkStateRequest getMarkStateDetail(String bah, int times, String type) {
        if (type.equals("DUPLICATE")) {
            return dao.selectExistRequest(bah, times);
        }
        return dao.selectExistRequest2(bah, times);
    }

    public Map<String, List<SheetOverview>> signedByDateCount(String signDate) {
        String start = signDate + " 00:00:00.000";
        String end = signDate + " 23:59:59.999";
        List<SheetOverview> list = dao.signedListByDate(start, end);
        Map<String, List<SheetOverview>> map = new HashMap<>();
        for (SheetOverview overview : list) {
            String key = overview.getSignStaff() + "-" + overview.getSignStaffName();
            if (map.containsKey(key)) {
                map.get(key).add(overview);
            } else {
                List<SheetOverview> tempList = new ArrayList<>();
                tempList.add(overview);
                map.put(key, tempList);
            }
        }
        return map;
    }

    public List<SheetOverview> getSheetsForAutoSign() {
        return dao.selectSheetsForAutoSign();
    }

    public String printVerifyForAutoSign(CaseFrontsheetMain sheet) {
        Integer status = dao.selectFileStatus(sheet.getBah(), sheet.getAdmissTimes());
        if (null != status && status == State.FileStatus.SIGNED) {
            return "OK";
        }
        sheet.setAddressMember(getStandardAddress(sheet.getStandardAddress()));
        ResultVo<List<CodeName>> save = saveSheet(sheet, null);
        if (!Objects.equals(save.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            return "校验未通过。";
        }
        Map<String, List<CodeName>> warnings = beginAnalyzeSheet(sheet);
        if (warnings.get("force").isEmpty()) {
            return "OK";
        }
        return "校验未通过。";
    }

    public void autoSign(CaseFrontsheetMain sheet) {
        String bah = sheet.getBah();
        int times = sheet.getAdmissTimes();
        insertSheetData(sheet);
        basDao.updateActFileStatus(bah, times, State.FileStatus.SIGNED);
    }

    public List<SheetOverview> getSimpleSheetForLendOut(String bah) {
        return dao.getSimpleSheetForLendOut(bah);
    }

    public String doLendOut(LendOutRequest request) {
        if (StringUtil.isBlank(request.getLendStaff())) {
            return "借阅人不能为空。";
        }
        if (StringUtil.isBlank(request.getRemark())) {
            return "备注不能为空。";
        }
        if (null == request.getList() || request.getList().isEmpty()) {
            return "借阅病案不能为空。";
        }
        request.setOpStaff(TokenUtil.getInstance().getTokenUserId());
        int insert = dao.insertLendOutInfo(request);
        if (insert == 0) {
            return "借阅记录失败。";
        }
        return "OK";
    }

    public List<LendOutSheet> getLendOutSheets() {
        return dao.selectLendOutSheets();
    }

    public String returnLendOutSheet(Integer id) {
        int update = dao.returnSheet(id);
        if (update == 0) {
            return "归还失败，请稍后重试。";
        }
        return "OK";
    }

    public LendOutRequest getLendOutDetail(String bah, int times) {
        return dao.selectExistLendOut(bah, times);
    }

    public List<BaOpLog> getBaOpLogs(String bah, Integer times) {
        return basDao.getBaOpLogs(bah, times);
    }

}
