package thyyxxk.webserver.service.medicalinsurance;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.util.UriEncoder;
import thyyxxk.webserver.config.envionment.MedinsurConfig;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.YesOrNo;
import thyyxxk.webserver.constants.sidicts.*;
import thyyxxk.webserver.dao.his.medicalinsurance.SiQueryDao;
import thyyxxk.webserver.dao.his.medicalinsurance.SiSetlinfoDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.markmtfees.MzVisit;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.InHspPsnInfo;
import thyyxxk.webserver.entity.medicalinsurance.outpatient.SpcChrDiseAcct;
import thyyxxk.webserver.entity.medicalinsurance.query.*;
import thyyxxk.webserver.entity.medicalinsurance.setlinfo.SiSetldetail;
import thyyxxk.webserver.entity.medicalinsurance.setlinfo.SiSetlinfo;
import thyyxxk.webserver.entity.medicalinsurance.setlinfo.TimesList;
import thyyxxk.webserver.entity.medicalinsurance.setllist.*;
import thyyxxk.webserver.entity.inpatient.ZyActpatient;
import thyyxxk.webserver.service.hutoolcache.RegionCache;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.utils.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

/**
 * @description: 医保查询服务
 * @author: DingJie
 * @create: 2021-06-23 16:35:23
 **/
@Slf4j
@Service
public class SiQueryService {
    private static final String RESULT_CODE = "infcode";
    private static final String ERROR_MESSAGE = "err_msg";
    private static final String OUTPUT = "output";
    private final ExecService exec;
    private final SiQueryDao dao;
    private final SiSetlinfoDao setlinfoDao;
    private final RegionCache regionCache;
    private final UserCache userCache;
    private final MedinsurConfig cfg;

    @Autowired
    public SiQueryService(ExecService exec, SiQueryDao dao, SiSetlinfoDao setlinfoDao, RegionCache regionCache, UserCache userCache, MedinsurConfig cfg) {
        this.exec = exec;
        this.dao = dao;
        this.setlinfoDao = setlinfoDao;
        this.regionCache = regionCache;
        this.userCache = userCache;
        this.cfg = cfg;
    }

    public ResultVo<SiPatInfo> getSiPatInfo(QryPsnBsInfo qryPsnBsInfo) {
        SiPatInfo siPatInfo = dao.selectSiPatInfo(qryPsnBsInfo.getPatNo(), qryPsnBsInfo.getTimes(), qryPsnBsInfo.getLedgerSn());
        if (null == siPatInfo) {
            siPatInfo = new SiPatInfo();
        }
        return ResultVoUtil.success(siPatInfo);
    }

    public ResultVo<PsnBaseInfo> obtainBasicPersonInfo(QryPsnBsInfo qryPsnBsInfo) {
        if (StringUtil.isBlank(qryPsnBsInfo.getReadCardResult())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "读卡内容不能为空，请先读卡！");
        }
        if (null == qryPsnBsInfo.getOnlyQry() && StringUtil.isBlank(qryPsnBsInfo.getMedType())) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请选择患者的医疗类别！");
        }
        if (null == qryPsnBsInfo.getLedgerSn()) {
            qryPsnBsInfo.setLedgerSn(0);
        }
        if (qryPsnBsInfo.getLedgerSn() != 0) {
            qryPsnBsInfo.setLedgerSn(dao.selectMaxLedgerSn(qryPsnBsInfo.getPatNo(), qryPsnBsInfo.getTimes()));
        }
        if (StringUtil.isBlank(qryPsnBsInfo.getStaffId())) {
            qryPsnBsInfo.setStaffId(TokenUtil.getInstance().getTokenUserId());
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OBTAIN_BASIC_PERSON_INFO, qryPsnBsInfo.getAdmdvs());
        JSONObject data = new JSONObject();

        data.put("psn_cert_type", "01");
        MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(qryPsnBsInfo.getMdtrtCertType());
        data.put("mdtrt_cert_type", mdtrtCertType.getCode());

        if (mdtrtCertType.getCode().equals(MdtrtCertType.SOCIAL_SECURITY_CARD.getCode())) {
            data.put("mdtrt_cert_no", qryPsnBsInfo.getReadCardResult().split("\\|")[2] + "|" + qryPsnBsInfo.getBusCardInfo());
            data.put("card_sn", qryPsnBsInfo.getReadCardResult().split("\\|")[3]);
            data.put("certno", qryPsnBsInfo.getReadCardResult().split("\\|")[1]);
        } else if (mdtrtCertType.getCode().equals(MdtrtCertType.MEDICAL_INSURANCE_ELECTRONIC_VOUCHER.getCode())) {
            JSONObject qrinfo = JSONObject.parseObject(qryPsnBsInfo.getReadCardResult());
            data.put("mdtrt_cert_no", qrinfo.getString("ecToken"));
            data.put("certno", qrinfo.getString("idNo"));
            data.put("psn_name", UriEncoder.decode(qrinfo.getString("userName")));
        }

        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.OBTAIN_BASIC_PERSON_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONObject baseinfo = output.getJSONObject("baseinfo");
            PsnBaseInfo psnBaseinfo = JSONObject.parseObject(baseinfo.toJSONString(), PsnBaseInfo.class);
            psnBaseinfo.setPatNo(qryPsnBsInfo.getPatNo());
            psnBaseinfo.setTimes(qryPsnBsInfo.getTimes());
            psnBaseinfo.setLedgerSn(qryPsnBsInfo.getLedgerSn());
            psnBaseinfo.setMedType(qryPsnBsInfo.getMedType());
            psnBaseinfo.setGendName(Gend.get(psnBaseinfo.getGend()).getName());
            psnBaseinfo.setPsnCertTypeName(PsnCertType.get(psnBaseinfo.getPsnCertType()).getName());
            Naty naty = Naty.get(psnBaseinfo.getNaty());
            if (null != naty) {
                psnBaseinfo.setNatyName(naty.getName());
            }
            List<IdetInfo> idetInfos = new ArrayList<>();
            JSONArray idet = output.getJSONArray("idetinfo");
            for (int i = 0; i < idet.size(); i++) {
                JSONObject item = idet.getJSONObject(i);
                IdetInfo info = JSONObject.parseObject(item.toJSONString(), IdetInfo.class);
                PsnIdetType psnIdetType = PsnIdetType.get(info.getPsnIdetType());
                if (null != psnIdetType) {
                    psnBaseinfo.setPsnIdetType(psnIdetType.getCode());
                    info.setPsnIdetTypeName(psnIdetType.getName());
                }
                idetInfos.add(info);
            }
            if (StringUtil.notBlank(psnBaseinfo.getPsnIdetType())) {
                dao.updatePsnIdetType(psnBaseinfo.getPsnIdetType(), psnBaseinfo.getPsnNo());
            }
            psnBaseinfo.setIdetinfo(idetInfos);
            if (new Integer(1).equals(qryPsnBsInfo.getNeedSaving())) {
                dao.updateZyActpatient(psnBaseinfo);
                psnBaseinfo.setBalc("0");
                int saved = dao.selectSiZyInfoCount(qryPsnBsInfo.getPatNo(), qryPsnBsInfo.getTimes(), qryPsnBsInfo.getLedgerSn());
                if (saved == 0) {
                    dao.insertSiZyInfoPsnNo(psnBaseinfo);
                } else {
                    dao.updateSiZyInfoPsnNo(psnBaseinfo);
                }
                log.info("患者基本信息已更新：{}", psnBaseinfo);
                output.put("times", qryPsnBsInfo.getTimes());
            }
            List<InsuInfo> list = new ArrayList<>();
            JSONArray insuinfo = output.getJSONArray("insuinfo");
            for (int i = 0; i < insuinfo.size(); i++) {
                JSONObject item = insuinfo.getJSONObject(i);
                InsuInfo info = JSONObject.parseObject(item.toJSONString(), InsuInfo.class);
                Insutype insutype = Insutype.get(info.getInsutype());
                if (null != insutype) {
                    info.setInsutypeName(insutype.getName());
                }
                PsnType psnType = PsnType.get(info.getPsnType());
                if (null != psnType) {
                    info.setPsnTypeName(psnType.getName());
                }
                if (null != info.getPsnInsuStas()) {
                    if (info.getPsnInsuStas().equals(YesOrNo.YES.getCodeStr())) {
                        info.setPsnInsuStasName("正常参保");
                    } else {
                        info.setPsnInsuStasName("暂停参保");
                    }
                }
                if (null != info.getCvlservFlag()) {
                    if (info.getCvlservFlag().equals(YesOrNo.YES.getCodeStr())) {
                        info.setCvlservFlagName("是");
                    } else {
                        info.setCvlservFlagName("否");
                    }
                }
                info.setInsuplcAdmdvsName(regionCache.get(info.getInsuplcAdmdvs()));
                list.add(info);
            }
            psnBaseinfo.setInsuinfo(list);
            return ResultVoUtil.success(psnBaseinfo);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<MedInsInfo>> obtainMedicalInstitutionInfo(String type, String fuzzyName) {
        JSONObject input = exec.makeTradeHeader(SiFunction.OBTAIN_MEDICAL_INSTITUTION_INFO);
        JSONObject medinsinfo = new JSONObject();
        medinsinfo.put("fixmedins_type", type);
        medinsinfo.put("fixmedins_name", fuzzyName);
        input.getJSONObject("input").put("medinsinfo", medinsinfo);
        JSONObject result = exec.executeTrade(input, SiFunction.OBTAIN_MEDICAL_INSTITUTION_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONArray output = result.getJSONObject(OUTPUT).getJSONArray("medinsinfo");
            List<MedInsInfo> list = new ArrayList<>();
            for (int i = 0; i < output.size(); i++) {
                JSONObject item = output.getJSONObject(i);
                MedInsInfo info = JSONObject.parseObject(item.toJSONString(), MedInsInfo.class);
                info.setFixmedinsAdmdvs(info.getFixmedinsCode().substring(1, 7));
                info.setFixmedinsAdmdvsName(regionCache.get(info.getFixmedinsAdmdvs()));
                FixmedinsType fixmedinsType = FixmedinsType.get(info.getFixmedinsType());
                if (null != fixmedinsType) {
                    info.setFixmedinsTypeName(fixmedinsType.getName());
                }
                HospLv hospLv = HospLv.get(info.getHospLv());
                if (null != hospLv) {
                    info.setHospLvName(hospLv.getName());
                }
                list.add(info);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<MdtrtInfo>> queryVisitInfo(BscQryPrm q) {
        CodeName codeName = dao.selectPsnNoByPatNoAndMedType(q.getPatNo(), q.getMedType());
        if (null == codeName) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有找到患者该医疗类别的我院就诊记录。");
        }
        q.setPsnNo(codeName.getName());
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_VISIT_INFO, codeName.getCode());
        String ref = JSONObject.toJSONStringWithDateFormat(q, "yyyy-MM-dd HH:mm:ss");
        input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_VISIT_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray mdts = output.getJSONArray("mdtrtinfo");
            List<MdtrtInfo> list = new ArrayList<>();
            for (int i = 0; i < mdts.size(); i++) {
                JSONObject item = mdts.getJSONObject(i);
                MdtrtInfo mdtrtInfo = JSONObject.parseObject(item.toJSONString(), MdtrtInfo.class);
                if (null != mdtrtInfo.getInsuOptins()) {
                    mdtrtInfo.setInsuOptinsName(regionCache.get(mdtrtInfo.getInsuOptins()));
                }
                SiEnumReflectUtil.mdtrtInfoReflect(mdtrtInfo);
                list.add(mdtrtInfo);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<DiseInfo>> queryDiagnosisInfo(BscQryPrm q) {
        String admdvs = dao.selectAdmdvsByPsnNo(q.getPsnNo());
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_DIAGNOSIS_INFO, admdvs);
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("mdtrt_id", q.getMdtrtId());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_DIAGNOSIS_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            List<DiseInfo> list = new ArrayList<>();
            JSONArray diseInfos = output.getJSONArray("diseinfo");
            for (int i = 0; i < diseInfos.size(); i++) {
                JSONObject item = diseInfos.getJSONObject(i);
                DiseInfo diseInfo = JSONObject.parseObject(item.toJSONString(), DiseInfo.class);
                SiEnumReflectUtil.diseInfoReflect(diseInfo);
                list.add(diseInfo);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<SetlInfo> querySettlementInfo(BscQryPrm q) {
        SiPatInfo siPatInfo = getSiPatInfo(q);
        if (null == siPatInfo) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到患者的医保登记信息！");
        }
        JSONObject output = execute5203(siPatInfo);
        JSONObject obj = output.getJSONObject("setlinfo");
        if (null == obj) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到该次就诊的结算明细。");
        }
        SetlInfo setlInfo = JSONObject.parseObject(obj.toJSONString(), SetlInfo.class);
        ClrType clrType = ClrType.get(setlInfo.getClrType());
        if (null != clrType) {
            setlInfo.setClrTypeName(clrType.getName());
        }
        MedType medType = MedType.get(setlInfo.getMedType());
        if (null != medType) {
            setlInfo.setMedTypeName(medType.getName());
        }
        PsnType psnType = PsnType.get(setlInfo.getPsnType());
        if (null != psnType) {
            setlInfo.setPsnTypeName(psnType.getName());
        }
        Insutype insutype = Insutype.get(setlInfo.getInsutype());
        if (null != insutype) {
            setlInfo.setInsutypeName(insutype.getName());
        }

        JSONArray setldetail = output.getJSONArray("setldetail");
        if (null != setldetail && !setldetail.isEmpty()) {
            List<SiSetldetail> list = new ArrayList<>();
            for (int i = 0; i < setldetail.size(); i++) {
                SiSetldetail setldtel = JSONObject.parseObject(setldetail.getJSONObject(i).toJSONString(), SiSetldetail.class);
                FundPayType fundPayType = FundPayType.get(setldtel.getFundPayType());
                if (null != fundPayType) {
                    setldtel.setFundPayTypeName(fundPayType.getName());
                }
                list.add(setldtel);
            }
            setlInfo.setSetldetail(list);
        }
        return ResultVoUtil.success(setlInfo);
    }

    public SiPatInfo getSiPatInfo(BscQryPrm q) {
        if (null == q.getMdtrtId()) {
            if (null == q.getLedgerSn()) {
                q.setLedgerSn(0);
            }
            return dao.selectSiPatInfo(q.getPatNo(), q.getTimes(), q.getLedgerSn());
        }
        return dao.selectSiPatInfoByMdtrtId(q.getMdtrtId());
    }

    public JSONObject execute5203(SiPatInfo siPatInfo) {
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_SETTLEMENT_INFO, siPatInfo.getInsuplcAdmdvs());
        JSONObject data = new JSONObject();
        data.put("psn_no", siPatInfo.getPsnNo());
        data.put("setl_id", siPatInfo.getSetlId());
        data.put("mdtrt_id", siPatInfo.getMdtrtId());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_SETTLEMENT_INFO);
        if (null == result) {
            throw new BizException(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            if (null == output.getJSONObject("setlinfo").getString("setl_id")) {
                throw new BizException(ExceptionEnum.LOGICAL_ERROR, "没有查询到患者的医保结算信息。");
            }
            return output;
        }
        throw new BizException(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<Map<String, Object>> queryFeeDetails(QryFeeDetl q) {
        SiPatInfo psninfo = dao.selectSiPatInfoByMdtrtId(q.getMdtrtId());
        if (null == psninfo) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的医保登记信息。");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("psninfo", psninfo);
        if (q.getSetlStatus().equals("unsettled")) {
            List<SiSetlFeeDetl> list = dao.selectTempCharge(psninfo.getPatNo(), psninfo.getTimes(), psninfo.getLedgerSn());
            if (null == list || list.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有已经上传的医保费用。");
            }
            map.put("feedtle", list);
            map.put("analyse", analyseFeedtle(list));
            return ResultVoUtil.success(map);
        }
        List<SiSetlFeeDetl> list = Objects.equals(q.getSetlType(), "11") ?
                dao.getMzFeeDetlList(psninfo.getMdtrtId(), psninfo.getPatNo(), psninfo.getTimes()) :
                dao.getZyFeeDetlList(psninfo.getMdtrtId(), psninfo.getPatNo(), psninfo.getTimes(), psninfo.getLedgerSn());
        if (!list.isEmpty()) {
            map.put("feedtle", list);
            map.put("analyse", analyseFeedtle(list));
            return ResultVoUtil.success(map);
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_FEE_DETAILS, psninfo.getInsuplcAdmdvs());
        JSONObject data = new JSONObject();
        data.put("psn_no", psninfo.getPsnNo());
        data.put("setl_id", psninfo.getSetlId());
        data.put("mdtrt_id", psninfo.getMdtrtId());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_FEE_DETAILS);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONArray output = result.getJSONArray(OUTPUT);
            if (null == output || output.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到费用明细。");
            }
            for (int i = 0; i < output.size(); i++) {
                JSONObject feeJson = output.getJSONObject(i);
                String feedetlSn = feeJson.getString("feedetl_sn");
                if (feedetlSn.contains("_")) {
                    String[] arr = feedetlSn.split("_");
                    feeJson.replace("feedetl_sn", arr[arr.length - 1]);
                }
                list.add(JSONObject.parseObject(feeJson.toJSONString(), SiSetlFeeDetl.class));
                if (list.size() == 30) {
                    dao.insertSetlFeeDetlBatch(list);
                    list.clear();
                }
            }
            if (!list.isEmpty()) {
                dao.insertSetlFeeDetlBatch(list);
            }
            list = dao.getZyFeeDetlList(psninfo.getMdtrtId(), psninfo.getPatNo(), psninfo.getTimes(), psninfo.getLedgerSn());
            map.put("feedtle", list);
            map.put("analyse", analyseFeedtle(list));
            return ResultVoUtil.success(map);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    private Map<String, String[]> analyseFeedtle(List<SiSetlFeeDetl> fees) {
        Map<String, String[]> map = new HashMap<>();
        map.put("zhj", new String[]{"合计", "0.00", "0.00", "0.00", "0.00"});
        fees.forEach(itm -> {
            ChrgitmLv chrgitmLv = ChrgitmLv.get(itm.getChrgitmLv());
            if (null == chrgitmLv) {
                chrgitmLv = ChrgitmLv.SELF_PAY;
                itm.setChrgitmLvName(chrgitmLv.getName());
            }
            String[] all = map.get("zhj");
            sumChargeFeeByType(itm, chrgitmLv, all);
            if (map.containsKey(itm.getMedChrgitmType())) {
                String[] dtle = map.get(itm.getMedChrgitmType());
                sumChargeFeeByType(itm, chrgitmLv, dtle);
            } else {
                String[] dtle = new String[5];
                MedChrgitmType type = MedChrgitmType.get(itm.getMedChrgitmType());
                if (type == null) {
                    type = MedChrgitmType.OTH;
                    itm.setMedChrgitmType(type.getCode());
                }
                dtle[0] = type.getName();
                dtle[1] = itm.getDetItemFeeSumamt();

                switch (chrgitmLv) {
                    case FIRST_CLASS:
                        dtle[2] = itm.getDetItemFeeSumamt();
                        dtle[3] = "0.00";
                        dtle[4] = "0.00";
                        break;
                    case SECOND_CLASS:
                        dtle[3] = itm.getDetItemFeeSumamt();
                        dtle[2] = "0.00";
                        dtle[4] = "0.00";
                        break;
                    case SELF_PAY:
                        dtle[4] = itm.getDetItemFeeSumamt();
                        dtle[3] = "0.00";
                        dtle[2] = "0.00";
                        break;
                }
                map.put(type.getCode(), dtle);
            }
        });
        String total = map.get("zhj")[1];
        for (Map.Entry<String, String[]> entry : map.entrySet()) {
            if (!entry.getKey().equals("zhj")) {
                String percentage = DecimalUtil.percentage(entry.getValue()[1], total);
                entry.getValue()[0] = entry.getValue()[0] + "(" + percentage + ")";
            }
        }
        return map;
    }

    private void sumChargeFeeByType(SiSetlFeeDetl itm, ChrgitmLv chrgitmLv, String[] dtle) {
        dtle[1] = DecimalUtil.add(dtle[1], itm.getDetItemFeeSumamt());
        switch (chrgitmLv) {
            case FIRST_CLASS:
                dtle[2] = DecimalUtil.add(dtle[2], itm.getDetItemFeeSumamt());
                break;
            case SECOND_CLASS:
                dtle[3] = DecimalUtil.add(dtle[3], itm.getDetItemFeeSumamt());
                break;
            case SELF_PAY:
                dtle[4] = DecimalUtil.add(dtle[4], itm.getDetItemFeeSumamt());
                break;
        }
    }

    public ResultVo<List<TrtInfo>> checkPersonTreatment(BscQryPrm q) {
        String admdvs = q.getAdmdvs();
        if (StringUtil.isBlank(admdvs)) {
            admdvs = dao.selectAdmdvs(q.getPatNo(), q.getTimes());
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(
                SiFunction.CHECK_PERSON_TREATMENT, admdvs);
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("insutype", q.getInsutype());
        data.put("fixmedins_code", cfg.getHospId());
        data.put("med_type", q.getMedType());
        data.put("begntime", DateUtil.formatDatetime(q.getBegntime()));
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.CHECK_PERSON_TREATMENT);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            List<TrtInfo> list = new ArrayList<>();
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray trtinfo = output.getJSONArray("trtinfo");
            for (int i = 0; i < trtinfo.size(); i++) {
                JSONObject obj = trtinfo.getJSONObject(i);
                TrtInfo item = JSONObject.parseObject(obj.toJSONString(), TrtInfo.class);
                TrtChkType trtChkType = TrtChkType.get(item.getTrtChkType());
                if (null != trtChkType) {
                    item.setTrtChkTypeName(trtChkType.getName());
                }
                FundPayType fundPayType = FundPayType.get(item.getFundPayType());
                if (null != fundPayType) {
                    item.setFundPayTypeName(fundPayType.getName());
                }
                if (null != item.getTrtEnjymntFlag()) {
                    if (item.getTrtEnjymntFlag().equals(YesOrNo.YES.getCodeStr())) {
                        item.setTrtEnjymntFlagName("是");
                    } else {
                        item.setTrtEnjymntFlagName("否");
                    }
                }
                list.add(item);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<InHspPsnInfo>> queryInHospitalPatientsInfo(BscQryPrm q) {
        if (StringUtil.notBlank(q.getPatNo())) {
            String psnNo = dao.selectPsnNo(q.getPatNo());
            if (null == psnNo) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【住院号/门诊号：" + q.getPatNo() + "】没有找到此患者在我院的医保在院信息，请核实。");
            }
            q.setPsnNo(psnNo);
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_IN_HOSPITAL_PATIENTS_INFO,
                dao.selectAdmdvsByPatNoAndPsnNo(q.getPatNo(), q.getPsnNo()));
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("begntime", DateUtil.formatDatetime(q.getBegntime()));
        data.put("endtime", null == q.getEndtime() ? DateUtil.now() : DateUtil.formatDatetime(q.getEndtime()));
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_IN_HOSPITAL_PATIENTS_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray pts = output.getJSONArray("data");
            if (pts.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到医保在院的患者信息。");
            }
            List<InHspPsnInfo> list = new ArrayList<>();
            for (int i = 0; i < pts.size(); i++) {
                JSONObject item = pts.getJSONObject(i);
                InHspPsnInfo inHspPsnInfo = JSONObject.parseObject(item.toJSONString(), InHspPsnInfo.class);
                SiEnumReflectUtil.inHspPsnInfoReflect(inHspPsnInfo);
                list.add(inHspPsnInfo);
            }
            if (list.size() == 1 && null != q.getTimes()) {
                InHspPsnInfo info = list.get(0);
                dao.updateInhospInfo(q.getPatNo(), q.getTimes(), q.getLedgerSn(), info.getMdtrtId(), info.getInsutype());
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<RefMedin>> queryPersonnelTransferHospitalInfo(BscQryPrm q) {
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_PERSONNEL_TRANSFER_HOSPITAL_INFO, dao.selectAdmdvsByPatNoAndPsnNo(q.getPatNo(), q.getPsnNo()));
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("begntime", DateUtil.formatDatetime(q.getBegntime()));
        data.put("endtime", DateUtil.formatDatetime(q.getEndtime()));
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_PERSONNEL_TRANSFER_HOSPITAL_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray array = output.getJSONArray("refmedin");
            if (null == array || array.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到符合条件的转院信息。");
            }
            List<RefMedin> list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = array.getJSONObject(i);
                RefMedin item = JSONObject.parseObject(obj.toJSONString(), RefMedin.class);
                Insutype insutype = Insutype.get(item.getInsutype());
                if (null != insutype) {
                    item.setInsutypeName(insutype.getName());
                }
                DclaSouc dclaSouc = DclaSouc.get(item.getDclaSouc());
                if (null != dclaSouc) {
                    item.setDclaSoucName(dclaSouc.getName());
                }
                PsnCertType psnCertType = PsnCertType.get(item.getPsnCertType());
                if (null != psnCertType) {
                    item.setPsnCertTypeName(psnCertType.getName());
                }
                item.setGendName(Gend.get(item.getGend()).getName());
                if (null != item.getInsuOptins()) {
                    item.setInsuOptinsName(regionCache.get(item.getInsuOptins()));
                }
                if (null != item.getOutFlag()) {
                    if (item.getOutFlag().equals(YesOrNo.YES.getCodeStr())) {
                        item.setOutFlagName("是");
                    } else {
                        item.setOutFlagName("否");
                    }
                }
                if (null != item.getHospAgreReflFlag()) {
                    if (item.getHospAgreReflFlag().equals(YesOrNo.YES.getCodeStr())) {
                        item.setHospAgreReflFlagName("是");
                    } else {
                        item.setHospAgreReflFlagName("否");
                    }
                }
                list.add(item);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<MedUseRcd>> querySpecialChronicDiseasesMedicalRecord(BscQryPrm q) {
        if (null == q.getPsnNo()) {
            String psnNo = dao.selectPsnNo(q.getPatNo());
            if (null == psnNo) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【住院号/门诊号：" + q.getPatNo() + "】未找到此患者的医保参保信息，请核实。");
            }
            q.setPsnNo(psnNo);
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_SPECIAL_CHRONIC_DISEASES_MEDICAL_RECORD, dao.selectAdmdvsByPsnNo(q.getPsnNo()));
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("begntime", DateUtil.formatDatetime(q.getBegntime()));
        data.put("endtime", DateUtil.formatDatetime(q.getEndtime()));
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_SPECIAL_CHRONIC_DISEASES_MEDICAL_RECORD);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray array = output.getJSONArray("feedetail");
            if (null == array || array.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到此人的慢特病用药记录。");
            }
            List<MedUseRcd> list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = array.getJSONObject(i);
                MedUseRcd item = JSONObject.parseObject(obj.toJSONString(), MedUseRcd.class);
                list.add(item);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<CumInfo>> queryPersonnelCumulativeInfo(BscQryPrm q) {
        String admdvs = q.getAdmdvs();
        if (StringUtil.isBlank(admdvs)) {
            admdvs = dao.selectAdmdvsByPsnNo(q.getPsnNo());
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_PERSONNEL_CUMULATIVE_INFO, admdvs);
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("cum_ym", q.getCumYm());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_PERSONNEL_CUMULATIVE_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray array = output.getJSONArray("cuminfo");
            List<CumInfo> list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = array.getJSONObject(i);
                CumInfo item = JSONObject.parseObject(obj.toJSONString(), CumInfo.class);
                Insutype insutype = Insutype.get(item.getInsutype());
                if (null != insutype) {
                    item.setInsutypeName(insutype.getName());
                }
                list.add(item);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<SpcChrDiseAcct>> querySpecialChronicDiseasesAccreditation(BscQryPrm q) {
        if (null == q.getPsnNo()) {
            String psnNo = dao.selectPsnNo(q.getPatNo());
            if (null == psnNo) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【住院号/门诊号：" + q.getPatNo() + "】未找到此患者的医保参保信息，请核实。");
            }
            q.setPsnNo(psnNo);
        }
        if (StringUtil.isBlank(q.getAdmdvs())) {
            String admdvs = StringUtil.isBlank(q.getPatNo()) ? dao.selectAdmdvsByPsnNo(q.getPsnNo()) : dao.selectAdmdvsByPatNo(q.getPatNo());
            q.setAdmdvs(admdvs);
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_SPECIAL_CHRONIC_DISEASES_ACCREDITATION, q.getAdmdvs());
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_SPECIAL_CHRONIC_DISEASES_ACCREDITATION);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray details = output.getJSONArray("feedetail");
            if (null == details || details.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有查询到此患者的慢特病备案信息。");
            }
            List<SpcChrDiseAcct> list = new ArrayList<>();
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DATE,-1);
            Date now = calendar.getTime();
            for (int i = 0; i < details.size(); i++) {
                JSONObject detail = details.getJSONObject(i);
                SpcChrDiseAcct spcChrDiseAcct = JSONObject.parseObject(detail.toJSONString(), SpcChrDiseAcct.class);
                if (null != q.getNeedAllRcd() && 1 == q.getNeedAllRcd()) {
                    list.add(spcChrDiseAcct);
                } else {
                    if (now.before(spcChrDiseAcct.getEnddate())) {
                        spcChrDiseAcct.setPatNo(q.getPatNo());
                        spcChrDiseAcct.setTimes(q.getTimes());
                        list.add(spcChrDiseAcct);
                    }
                }
            }
            if (!list.isEmpty()) {
                return ResultVoUtil.success(list);
            }
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的慢特病备案，或慢特病备案已过期！");
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<PsnFixMedin>> queryPersonnelAssignmentInfo(BscQryPrm q) {
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_PERSONNEL_ASSIGNMENT_INFO, q.getAdmdvs());
        JSONObject data = new JSONObject();
        data.put("psn_no", q.getPsnNo());
        data.put("biz_appy_type", q.getBizAppyType());
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_PERSONNEL_ASSIGNMENT_INFO);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (result.getIntValue(RESULT_CODE) == 0) {
            JSONObject output = result.getJSONObject(OUTPUT);
            JSONArray array = output.getJSONArray("psnfixmedin");
            if (null == array || array.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有查询到对应的定点信息。");
            }
            List<PsnFixMedin> list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = array.getJSONObject(i);
                PsnFixMedin item = JSONObject.parseObject(obj.toJSONString(), PsnFixMedin.class);
                Insutype insutype = Insutype.get(item.getInsutype());
                if (null != insutype) {
                    item.setInsutypeName(insutype.getName());
                }
                list.add(item);
            }
            return ResultVoUtil.success(list);
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
    }

    public ResultVo<List<TimesList>> fetchSiTimesList(String patNo, Integer type) {
        List<TimesList> list = dao.fetchSiTimesList(patNo, type);
        if (type == 11) {
            List<TimesList> mipList = dao.getMipayTimesList(patNo + "%");
            for (TimesList mip : mipList) {
                String[] arr = mip.getHisOrdNum().split("_");
                mip.setTimes(Integer.parseInt(arr[1]));
                mip.setLedgerSn(0);
                list.add(mip);
            }
        }
        if (list.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "此患者没有有效的结算信息。");
        }
        return ResultVoUtil.success(list);
    }

    public ResultVo<String> queryInsuplcAdmdvsByMdtrtId(String mdtrtId) {
        return ResultVoUtil.success(dao.selectInsuplcAdmdvsByMdtrtId(mdtrtId));
    }

    public ResultVo<InptntSetlmtLst> queryInpatientSetlList(SetlIndex index) {
        if (null == index.getTimes() && StringUtil.isBlank(index.getLabel())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "结算条目不能为空！");
        }
        String[] arr = index.getLabel().split("_");
        if (StringUtil.notBlank(index.getLabel()) && !index.getPatNo().contains("-")) {
            index.setSetlId(arr[0]);
            index.setTimes(Integer.parseInt(arr[1]));
            index.setLedgerSn(Integer.parseInt(arr[2]));
        } else {
            index.setLedgerSn(0);
            index.setTimes(Integer.parseInt(arr[1]));
            index.setSetlId(dao.selectSetlId(index.getPatNo(), index.getTimes(), index.getLedgerSn()));
        }
        SiPatInfo siPatInfo = dao.selectSiPatInfo(index.getPatNo(), index.getTimes(), index.getLedgerSn());
        if (null == siPatInfo) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的结算信息！");
        }
        CuminfoInYear cuminfo = getYearCuminfo(index.getSetlId(), siPatInfo.getPsnNo(), siPatInfo.getInsuplcAdmdvs());
        if (!Objects.equals(cuminfo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, cuminfo.getMessage());
        }
        InptntSetlmtLst lst;
        if (index.getLedgerSn() == 0) {
            lst = dao.selectJzSetlinfo(index.getSetlId());
        } else {
            lst = dao.selectZySetlinfo(index.getSetlId(), "zy_inactpatient");
            if (null == lst) {
                lst = dao.selectZySetlinfo(index.getSetlId(), "zy_actpatient");
                if (null == lst) {
                    return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的结算信息！");
                }
            }
        }
        lst.setInHospdays(DateUtil.daysBetween(lst.getEndtime(), lst.getBegntime()));
        PsnIdetType psnIdetType = PsnIdetType.get(lst.getPsnIdetType());
        if (null != psnIdetType) {
            lst.setPsnIdetTypeName(psnIdetType.getName());
        }
        Admdvs admdvs = Admdvs.get(lst.getInsuplcAdmdvs());
        if (null == admdvs) {
            lst.setInsuplcAdmdvsName(regionCache.get(lst.getInsuplcAdmdvs()));
        } else {
            lst.setInsuplcAdmdvsName(admdvs.getName());
        }
        lst.setFixmedinsName(cfg.getHospName());
        lst.setGendName(Gend.get(lst.getGend()).getName());
        SiEnumReflectUtil.inptntSetlmtLstReflect(lst);
        ResultVo<List<SiSetlFeeDetl>> chrgrsvo = getChrgitems(lst.getPsnNo(), lst.getSetlId(), lst.getMdtrtId(), lst.getInsuplcAdmdvs());
        if (!chrgrsvo.getCode().equals(ExceptionEnum.SUCCESS.getCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, chrgrsvo.getMessage());
        }
        ChrgItemLvInfo chrgItemLvInfo = analyzeParticularChrgitmLv(chrgrsvo.getData());
        lst.setChrgItemLvInfo(chrgItemLvInfo);
        lst.setCuminfo(cuminfo);
        ResultVo<PolItemInfo> polItemRes = listPolItemCodePayInfo(lst.getPsnNo(), lst.getMdtrtId(), lst.getSetlId(), lst.getInsuplcAdmdvs());
        if (!Objects.equals(polItemRes.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, polItemRes.getMessage());
        }
        lst.setPolItemInfo(polItemRes.getData());
        return ResultVoUtil.success(lst);
    }

    public ResultVo<OtptntSetlmtLst> queryOutpatientSetlList(SetlIndex index) {
        if (null == index.getTimes() && StringUtil.isBlank(index.getLabel())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "结算条目不能为空！");
        }
        index.setLedgerSn(0);
        if (StringUtil.notBlank(index.getLabel())) {
            String[] arr = index.getLabel().split("_");
            index.setSetlId(arr[0]);
            index.setTimes(Integer.parseInt(arr[1]));
            if (arr[2].contains("^")) {
                index.setHisOrdNum(arr[2].replaceAll("\\^", "_"));
            }
        } else {
            index.setSetlId(dao.selectSetlId(index.getPatNo(), index.getTimes(), index.getLedgerSn()));
        }
        SiPatInfo siPatInfo;
        if (StringUtil.isBlank(index.getHisOrdNum())) {
            siPatInfo = dao.selectSiPatInfo(index.getPatNo(), index.getTimes(), index.getLedgerSn());
        } else {
            siPatInfo = dao.selectSiPatInfo2(index.getHisOrdNum());
        }
        if (null == siPatInfo) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的结算信息！");
        }
        CuminfoInYear cuminfo = getYearCuminfo(index.getSetlId(), siPatInfo.getPsnNo(), siPatInfo.getInsuplcAdmdvs());
        if (!Objects.equals(cuminfo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, cuminfo.getMessage());
        }
        OtptntSetlmtLst lst;
        if (StringUtil.isBlank(index.getHisOrdNum())) {
            lst = dao.selectMzSetlifo(index.getPatNo(), index.getTimes());
        } else {
            String hiExtData = dao.getHiExtData(index.getHisOrdNum());
            if (StringUtil.isBlank(hiExtData)) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的结算信息！");
            }
            MzVisit mzVisit = dao.getMzVisit(index);
            if (null == mzVisit) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的就诊信息！");
            }
            JSONObject obj = JSONObject.parseObject(hiExtData);
            JSONObject setlObj = obj.getJSONObject("setlinfo");
            lst = JSONObject.toJavaObject(setlObj, OtptntSetlmtLst.class);
            lst.setAdmDeptName(mzVisit.getVisitDeptName());
            lst.setBegntime(mzVisit.getVisitDate());
            lst.setDiseName(mzVisit.getIcdText().split(",")[0]);
            lst.setChfpdrName(mzVisit.getDoctorCode());
        }
        if (null == lst) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到此患者的结算信息！");
        }
        lst.setPsnCertTypeName(PsnCertType.get(lst.getPsnCertType()).getName());
        lst.setPsnIdetTypeName(PsnIdetType.getName(lst.getPsnIdetType()));
        lst.setChfpdrName(userCache.getEmployeeName(lst.getChfpdrName()));
        Admdvs admdvs = Admdvs.get(lst.getInsuplcAdmdvs());
        if (null == admdvs) {
            lst.setInsuplcAdmdvsName(regionCache.get(lst.getInsuplcAdmdvs()));
        } else {
            lst.setInsuplcAdmdvsName(admdvs.getName());
        }
        SiEnumReflectUtil.outptntSetlmtLstReflect(lst);
        List<BrfChrgitm> chrgitms = dao.selectMzBrfChrgitms(index.getPatNo(), index.getTimes());
        lst.setCuminfo(cuminfo);
        lst.setFixmedinsName(cfg.getHospName());
        Insutype insutype = Insutype.get(lst.getInsutype());
        if (insutype == Insutype.BASIC_MEDICAL_INSURANCE_FOR_EMPLOYEES) {
            ResultVo<List<SiSetlFeeDetl>> chrgrsvo = getChrgitems(lst.getPsnNo(), lst.getSetlId(), lst.getMdtrtId(), lst.getInsuplcAdmdvs());
            if (!chrgrsvo.getCode().equals(ExceptionEnum.SUCCESS.getCode())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, chrgrsvo.getMessage());
            }
            ChrgItemLvInfo chrgItemLvInfo = analyzeParticularChrgitmLv(chrgrsvo.getData());
            lst.setChrgItemLvInfo(chrgItemLvInfo);
            ResultVo<PolItemInfo> polItemRes = listPolItemCodePayInfo(lst.getPsnNo(), lst.getMdtrtId(), lst.getSetlId(), lst.getInsuplcAdmdvs());
            if (!Objects.equals(polItemRes.getCode(), ExceptionEnum.SUCCESS.getCode())) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, polItemRes.getMessage());
            }
            lst.setPolItemInfo(polItemRes.getData());
        } else {
            analyzeMzChrgitm(lst, chrgitms);
        }
        return ResultVoUtil.success(lst);
    }

    private ResultVo<PolItemInfo> listPolItemCodePayInfo(String psnNo, String mdtrtId, String setlId, String insuplc) {
//        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.LIST_POL_ITEM_CODE_PAY_INFO, insuplc);
//        JSONObject data = new JSONObject();
//        data.put("psn_no", psnNo);
//        data.put("mdtrt_id", mdtrtId);
//        data.put("setl_id", setlId);
//        input.getJSONObject("input").put("data", data);
//        JSONObject result = exec.executeTrade(input, SiFunction.LIST_POL_ITEM_CODE_PAY_INFO);
//        if (null == result) {
//            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
//        }
//        if (null == result.getInteger("code")) {
//            String message = result.getString("message");
//            if (null == message) {
//                message = result.getString(ERROR_MESSAGE);
//            }
//            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + message);
//        }
//        if (result.getIntValue("code") != 0) {
//            String message = result.getString("message");
//            if (null == message) {
//                message = result.getString(ERROR_MESSAGE);
//            }
//            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心出错：" + message);
//        }
//        PolItemInfo polItemInfo = new PolItemInfo();
//        JSONArray array = result.getJSONArray("data");
//        BigDecimal selfPaySum = new BigDecimal(0);
//        BigDecimal fundPaySum = new BigDecimal(0);
//        List<PolicyItem> policyItems = new ArrayList<>();
//        for (int i = 0; i < array.size(); i++) {
//            JSONObject polObj = array.getJSONObject(i);
//            PolicyItem policyItem = JSONObject.parseObject(JSONObject.toJSONString(polObj), PolicyItem.class);
//            policyItems.add(policyItem);
//            selfPaySum = selfPaySum.add(policyItem.getSelfPayAmt());
//            fundPaySum = fundPaySum.add(policyItem.getFundPayAmt());
//        }
//        polItemInfo.setAllPsnAmt(selfPaySum);
//        polItemInfo.setAllFundAmt(fundPaySum);
//        polItemInfo.setAllSum(fundPaySum.add(selfPaySum));
//        polItemInfo.setPolicyItems(policyItems);
        return ResultVoUtil.success(new PolItemInfo());
    }

    public CuminfoInYear getYearCuminfo(String setlId, String psnNo, String admdvs) {
        CuminfoInYear cuminfo = dao.selectCumInfo(setlId);
        if (null != cuminfo) {
            cuminfo.setCode(ExceptionEnum.SUCCESS.getCode());
            return cuminfo;
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_PERSONNEL_CUMULATIVE_INFO, admdvs);
        JSONObject data = new JSONObject();
        data.put("psn_no", psnNo);
        data.put("cum_ym", "");
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_PERSONNEL_CUMULATIVE_INFO);
        cuminfo = new CuminfoInYear();
        if (null == result) {
            cuminfo.setCode(ExceptionEnum.NETWORK_ERROR.getCode());
            cuminfo.setMessage(ExceptionEnum.NETWORK_ERROR.getMessage());
            return cuminfo;
        }
        if (null == result.getInteger(RESULT_CODE)) {
            cuminfo.setCode(ExceptionEnum.LOGICAL_ERROR.getCode());
            cuminfo.setMessage("医保中心报错：" + result.getString("message"));
            return cuminfo;
        }
        if (result.getIntValue(RESULT_CODE) != 0) {
            cuminfo.setCode(ExceptionEnum.NETWORK_ERROR.getCode());
            cuminfo.setMessage("医保中心出错：" + result.getString("message"));
            return cuminfo;
        }
        cuminfo.setCode(ExceptionEnum.SUCCESS.getCode());
        String year = String.valueOf(LocalDate.now().getYear());
        JSONArray cuminfos = result.getJSONObject(OUTPUT).getJSONArray("cuminfo");
        log.info("累计信息：{}", cuminfos);
        for (int i = 0; i < cuminfos.size(); i++) {
            JSONObject itm = cuminfos.getJSONObject(i);
            if (itm.getString("year").equals(year)) {
                switch (itm.getString("cum_type_code")) {
                    // 本年住院次数
                    case "C0000_BIZ2101":
                    case "C0000_BIZ2102":
                    case "C0000_BIZ2106":
                    case "C0000_BIZ2107":
                    case "C0000_BIZ22":
                    case "C0000_BIZ52":
                        cuminfo.addYearAdmtimesZy(itm.getDoubleValue("cum"));
                        break;
                    // 本年门诊次数
                    case "C0000_BIZ11":
                    case "C0000_BIZ13":
                    case "C0000_BIZ14":
                    case "C0000_BIZ51":
                    case "C0000_BIZ9901":
                    case "C0000_BIZ9903":
                    case "C0000_BIZ9904":
                        cuminfo.addYearAdmtimesMz(itm.getDoubleValue("cum"));
                        break;
                    // 本年度住院分段计算费用累计
                    case "S0000_BIZ2101":
                    case "S0000_BIZ2102":
                    case "S0000_BIZ2106":
                    case "S0000_BIZ2107":
                    case "S0000_BIZ22":
                    case "S0000_BIZ52":
                        cuminfo.addYearPeriodFeeSumZy(itm.getDoubleValue("cum"));
                        break;
                    // 本年度门诊分段计算费用累计
                    case "S0000_BIZ11":
                    case "S0000_BIZ13":
                    case "S0000_BIZ14":
                    case "S0000_BIZ51":
                    case "S0000_BIZ9901":
                    case "S0000_BIZ9903":
                    case "S0000_BIZ9904":
                        cuminfo.addYearPeriodFeeSumMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院医疗费合计
                    case "F0000_BIZ2101":
                    case "F0000_BIZ2102":
                    case "F0000_BIZ2106":
                    case "F0000_BIZ2107":
                    case "F0000_BIZ22":
                    case "F0000_BIZ52":
                        cuminfo.addYearFeeSumZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊医疗费合计
                    case "F0000_BIZ11":
                    case "F0000_BIZ13":
                    case "F0000_BIZ14":
                    case "F0000_BIZ51":
                    case "F0000_BIZ9901":
                    case "F0000_BIZ9903":
                    case "F0000_BIZ9904":
                        cuminfo.addYearFeeSumMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院已付起付线
                    case "Q0000_BIZ2101":
                    case "Q0000_BIZ2102":
                    case "Q0000_BIZ2106":
                    case "Q0000_BIZ2107":
                    case "Q0000_BIZ22":
                    case "Q0000_BIZ52":
                        cuminfo.addYearPayedbegnlineZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊已付起付线
                    case "Q0000_BIZ11":
                    case "Q0000_BIZ13":
                    case "Q0000_BIZ14":
                    case "Q0000_BIZ51":
                    case "Q0000_BIZ9901":
                    case "Q0000_BIZ9903":
                    case "Q0000_BIZ9904":
                        cuminfo.addYearPayedbegnlineMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院统筹支付
                    case "D310101_BIZ2101":
                    case "D310101_BIZ2102":
                    case "D310101_BIZ2106":
                    case "D310101_BIZ2107":
                    case "D310101_BIZ22":
                    case "D310101_BIZ52":
                    case "D390101_BIZ2101":
                    case "D390101_BIZ2102":
                    case "D390101_BIZ2106":
                    case "D390101_BIZ2107":
                    case "D390101_BIZ22":
                    case "D390101_BIZ52":
                        cuminfo.addYearFundpaysZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊统筹支付
                    case "D310101_BIZ11":
                    case "D310101_BIZ13":
                    case "D310101_BIZ14":
                    case "D310101_BIZ51":
                    case "D310101_BIZ9901":
                    case "D310101_BIZ9903":
                    case "D310101_BIZ9904":
                    case "D390101_BIZ11":
                    case "D390101_BIZ13":
                    case "D390101_BIZ14":
                    case "D390101_BIZ51":
                    case "D390101_BIZ9901":
                    case "D390101_BIZ9903":
                    case "D390101_BIZ9904":
                        cuminfo.addYearFundpaysMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院政策自费
                    case "Z0000_BIZ2101_LAB101":
                    case "Z0000_BIZ2102_LAB101":
                    case "Z0000_BIZ22_LAB101":
                    case "Z0000_BIZ2106_LAB101":
                    case "Z0000_BIZ2107_LAB101":
                    case "Z0000_BIZ52_LAB101":
                    case "Z0000_BIZ2101_LAB103":
                    case "Z0000_BIZ2102_LAB103":
                    case "Z0000_BIZ22_LAB103":
                    case "Z0000_BIZ2106_LAB103":
                    case "Z0000_BIZ2107_LAB103":
                    case "Z0000_BIZ52_LAB103":
                        cuminfo.addYearPolicySelfpayZy(itm.getDoubleValue("cum"));
                        break;
                    // 住院政策自付
                    case "Z0000_BIZ2101_LAB102":
                    case "Z0000_BIZ2102_LAB102":
                    case "Z0000_BIZ22_LAB102":
                    case "Z0000_BIZ2106_LAB102":
                    case "Z0000_BIZ2107_LAB102":
                    case "Z0000_BIZ52_LAB102":
                        cuminfo.addYearPreSelfpayZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊政策自费
                    case "Z0000_BIZ11_LAB101":
                    case "Z0000_BIZ13_LAB101":
                    case "Z0000_BIZ14_LAB101":
                    case "Z0000_BIZ51_LAB101":
                    case "Z0000_BIZ9901_LAB101":
                    case "Z0000_BIZ9903_LAB101":
                    case "Z0000_BIZ9904_LAB101":
                    case "Z0000_BIZ11_LAB103":
                    case "Z0000_BIZ13_LAB103":
                    case "Z0000_BIZ14_LAB103":
                    case "Z0000_BIZ51_LAB103":
                    case "Z0000_BIZ9901_LAB103":
                    case "Z0000_BIZ9903_LAB103":
                    case "Z0000_BIZ9904_LAB103":
                        cuminfo.addYearPolicySelfpayMz(itm.getDoubleValue("cum"));
                        break;
                    // 门诊政策自付
                    case "Z0000_BIZ11_LAB102":
                    case "Z0000_BIZ13_LAB102":
                    case "Z0000_BIZ14_LAB102":
                    case "Z0000_BIZ51_LAB102":
                    case "Z0000_BIZ9901_LAB102":
                    case "Z0000_BIZ9903_LAB102":
                    case "Z0000_BIZ9904_LAB102":
                        cuminfo.addYearPreSelfpayMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院大额基金支付
                    case "D330101_BIZ2101":
                    case "D330101_BIZ2102":
                    case "D330101_BIZ2106":
                    case "D330101_BIZ2107":
                    case "D330101_BIZ22":
                    case "D330101_BIZ52":
                        cuminfo.addYearBigAmtpaysZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊大额基金支付
                    case "D330101_BIZ11":
                    case "D330101_BIZ13":
                    case "D330101_BIZ14":
                    case "D330101_BIZ51":
                    case "D330101_BIZ9901":
                    case "D330101_BIZ9903":
                    case "D330101_BIZ9904":
                        cuminfo.addYearBigAmtpaysMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院大病保险支付
                    case "D390201_BIZ2101":
                    case "D390201_BIZ2102":
                    case "D390201_BIZ2106":
                    case "D390201_BIZ2107":
                    case "D390201_BIZ22":
                    case "D390201_BIZ52":
                        cuminfo.addYearBigdssInspaysZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊大病保险支付
                    case "D390201_BIZ11":
                    case "D390201_BIZ13":
                    case "D390201_BIZ14":
                    case "D390201_BIZ51":
                    case "D390201_BIZ9901":
                    case "D390201_BIZ9903":
                    case "D390201_BIZ9904":
                        cuminfo.addYearBigdssInspaysMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院医疗救助支付
                    case "D610101_BIZ2101":
                    case "D610101_BIZ2102":
                    case "D610101_BIZ2106":
                    case "D610101_BIZ2107":
                    case "D610101_BIZ22":
                    case "D610101_BIZ52":
                        cuminfo.addYearMafpaysZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊医疗救助支付
                    case "D610101_BIZ11":
                    case "D610101_BIZ13":
                    case "D610101_BIZ14":
                    case "D610101_BIZ51":
                    case "D610101_BIZ9901":
                    case "D610101_BIZ9903":
                    case "D610101_BIZ9904":
                        cuminfo.addYearMafpaysMz(itm.getDoubleValue("cum"));
                        break;
                    // 住院个人账户支付
                    case "D310201_BIZ2101":
                    case "D310201_BIZ2102":
                    case "D310201_BIZ2106":
                    case "D310201_BIZ2107":
                    case "D310201_BIZ22":
                    case "D310201_BIZ52":
                        cuminfo.addYearAcctPayZy(itm.getDoubleValue("cum"));
                        break;
                    // 门诊个人账户支付
                    case "D310201_BIZ11":
                    case "D310201_BIZ13":
                    case "D310201_BIZ14":
                    case "D310201_BIZ51":
                    case "D310201_BIZ9901":
                    case "D310201_BIZ9903":
                    case "D310201_BIZ9904":
                        cuminfo.addYearAcctPayMz(itm.getDoubleValue("cum"));
                        break;
                    // 大病保险合规费用
                    case "TS390201":
                        cuminfo.addYearBigdssLegalFee(itm.getDoubleValue("cum"));
                        break;
                }
            }
        }
        return cuminfo;
    }

    public ResultVo<List<SiSetlFeeDetl>> getChrgitems(SiSetlinfo setlinfo) {
        return getChrgitems(setlinfo.getPsnNo(), setlinfo.getSetlId(), setlinfo.getMdtrtId(), setlinfo.getInsuplcAdmdvs());
    }

    private ResultVo<List<SiSetlFeeDetl>> getChrgitems(String psnNo, String setlId, String mdtrtId, String admdvs) {
        List<SiSetlFeeDetl> list = dao.selectAllSetlFeeDtle(mdtrtId);
        if (!list.isEmpty()) {
            return ResultVoUtil.success(list);
        }
        JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.QUERY_FEE_DETAILS, admdvs);
        JSONObject data = new JSONObject();
        data.put("psn_no", psnNo);
        data.put("setl_id", setlId);
        data.put("mdtrt_id", mdtrtId);
        input.getJSONObject("input").put("data", data);
        JSONObject result = exec.executeTrade(input, SiFunction.QUERY_FEE_DETAILS);
        if (null == result) {
            return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
        }
        if (null == result.getInteger(RESULT_CODE)) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错：" + result.getString("message"));
        }
        if (0 == result.getInteger(RESULT_CODE)) {
            JSONArray output = result.getJSONArray(OUTPUT);
            if (null == output || output.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "没有查询到费用明细。");
            }
            for (int i = 0; i < output.size(); i++) {
                JSONObject feeItem = output.getJSONObject(i);
                feeItem.replace("feedetl_sn", i + 1);
                SiSetlFeeDetl fee = JSONObject.parseObject(feeItem.toJSONString(), SiSetlFeeDetl.class);
                if (StringUtil.isBlank(fee.getSetlId())) {
                    fee.setSetlId(setlId);
                }
                list.add(fee);
                if (list.size() == 30) {
                    dao.insertSetlFeeDetlBatch(list);
                    list.clear();
                }
            }
            if (!list.isEmpty()) {
                dao.insertSetlFeeDetlBatch(list);
            }
            return ResultVoUtil.success(dao.selectAllSetlFeeDtle(mdtrtId));
        }
        return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, result.getString(ERROR_MESSAGE));
    }

    private ChrgItemLvInfo analyzeParticularChrgitmLv(List<SiSetlFeeDetl> chrgitms) {
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("allfeeSum", new BigDecimal(0));
        map.put("totalFrst", new BigDecimal(0));
        map.put("totalScnd", new BigDecimal(0));
        map.put("totalThrd", new BigDecimal(0));
        chrgitms.forEach(itm -> {
            BigDecimal itmfeeSum = new BigDecimal(itm.getDetItemFeeSumamt());
            map.replace("allfeeSum", map.get("allfeeSum").add(itmfeeSum));
            if (itm.getChrgitmLv().equals(ChrgitmLv.FIRST_CLASS.getCode())) {
                map.replace("totalFrst", map.get("totalFrst").add(itmfeeSum));
            } else if (itm.getChrgitmLv().equals(ChrgitmLv.SECOND_CLASS.getCode())) {
                map.replace("totalScnd", map.get("totalScnd").add(itmfeeSum));
            } else {
                map.replace("totalThrd", map.get("totalThrd").add(itmfeeSum));
            }
            String typeKey = itm.getMedChrgitmType();
            String lvKey = typeKey + "-" + itm.getChrgitmLv();
            if (map.containsKey(typeKey)) {
                map.replace(typeKey, map.get(typeKey).add(itmfeeSum));
            } else {
                map.put(typeKey, itmfeeSum);
            }
            if (map.containsKey(lvKey)) {
                map.replace(lvKey, map.get(lvKey).add(itmfeeSum));
            } else {
                map.put(lvKey, itmfeeSum);
            }
        });
        ChrgItemLvInfo chrgItemLvInfo = new ChrgItemLvInfo();
        chrgItemLvInfo.setAllfeeSum(map.get("allfeeSum"));
        chrgItemLvInfo.setAllfeeFrst(map.get("totalFrst"));
        chrgItemLvInfo.setAllfeeScnd(map.get("totalScnd"));
        chrgItemLvInfo.setAllfeeThrd(map.get("totalThrd"));
        chrgItemLvInfo.setWestMedFeeSum(map.get("09"));
        chrgItemLvInfo.setWestMedFeeFrst(map.get("09-01"));
        chrgItemLvInfo.setWestMedFeeScnd(map.get("09-02"));
        chrgItemLvInfo.setWestMedFeeThrd(map.get("09-03"));
        chrgItemLvInfo.setHerbalSum(map.get("10"));
        chrgItemLvInfo.setHerbalFrst(map.get("10-01"));
        chrgItemLvInfo.setHerbalScnd(map.get("10-02"));
        chrgItemLvInfo.setHerbalThrd(map.get("10-03"));
        chrgItemLvInfo.setChnsPtntSum(map.get("11"));
        chrgItemLvInfo.setChnsPtntFrst(map.get("11-01"));
        chrgItemLvInfo.setChnsPtntScnd(map.get("11-02"));
        chrgItemLvInfo.setChnsPtntThrd(map.get("11-03"));
        chrgItemLvInfo.setClinicSum(map.get("02"));
        chrgItemLvInfo.setClinicFrst(map.get("02-01"));
        chrgItemLvInfo.setClinicScnd(map.get("02-02"));
        chrgItemLvInfo.setClinicThrd(map.get("02-03"));
        chrgItemLvInfo.setTreatSum(map.get("05"));
        chrgItemLvInfo.setTreatFrst(map.get("05-01"));
        chrgItemLvInfo.setTreatScnd(map.get("05-02"));
        chrgItemLvInfo.setTreatThrd(map.get("05-03"));
        chrgItemLvInfo.setSurgerySum(map.get("06"));
        chrgItemLvInfo.setSurgeryFrst(map.get("06-01"));
        chrgItemLvInfo.setSurgeryScnd(map.get("06-02"));
        chrgItemLvInfo.setSurgeryThrd(map.get("06-03"));
        chrgItemLvInfo.setNursingSum(map.get("07"));
        chrgItemLvInfo.setNursingFrst(map.get("07-01"));
        chrgItemLvInfo.setNursingScnd(map.get("07-02"));
        chrgItemLvInfo.setNursingThrd(map.get("07-03"));
        chrgItemLvInfo.setSntryMtrlsSum(map.get("08"));
        chrgItemLvInfo.setSntryMtrlsFrst(map.get("08-01"));
        chrgItemLvInfo.setSntryMtrlsScnd(map.get("08-02"));
        chrgItemLvInfo.setSntryMtrlsThrd(map.get("08-03"));
        chrgItemLvInfo.setExamSum(map.get("04"));
        chrgItemLvInfo.setExamFrst(map.get("04-01"));
        chrgItemLvInfo.setExamScnd(map.get("04-02"));
        chrgItemLvInfo.setExamThrd(map.get("04-03"));
        chrgItemLvInfo.setNrmlTrtmtSum(map.get("12"));
        chrgItemLvInfo.setNrmlTrtmtFrst(map.get("12-01"));
        chrgItemLvInfo.setNrmlTrtmtScnd(map.get("12-02"));
        chrgItemLvInfo.setNrmlTrtmtThrd(map.get("12-03"));
        chrgItemLvInfo.setInspectSum(map.get("03"));
        chrgItemLvInfo.setInspectFrst(map.get("03-01"));
        chrgItemLvInfo.setInspectScnd(map.get("03-02"));
        chrgItemLvInfo.setInspectThrd(map.get("03-03"));
        chrgItemLvInfo.setRegisterSum(map.get("13"));
        chrgItemLvInfo.setRegisterFrst(map.get("13-01"));
        chrgItemLvInfo.setRegisterScnd(map.get("13-02"));
        chrgItemLvInfo.setRegisterThrd(map.get("13-03"));
        chrgItemLvInfo.setBedfeeSum(map.get("01"));
        chrgItemLvInfo.setBedfeeFrst(map.get("01-01"));
        chrgItemLvInfo.setBedfeeScnd(map.get("01-02"));
        chrgItemLvInfo.setBedfeeThrd(map.get("01-03"));
        chrgItemLvInfo.setOthfeeSum(map.get("14"));
        chrgItemLvInfo.setOthfeeFrst(map.get("14-01"));
        chrgItemLvInfo.setOthfeeScnd(map.get("14-02"));
        chrgItemLvInfo.setOthfeeThrd(map.get("14-03"));
        return chrgItemLvInfo;
    }

    private void analyzeMzChrgitm(OtptntSetlmtLst lst, List<BrfChrgitm> chrgitms) {
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("allfeeSum", BigDecimal.valueOf(0));
        map.put("totalThrd", BigDecimal.valueOf(0));
        map.put("totalScnd", BigDecimal.valueOf(0));
        map.put("othSum", BigDecimal.valueOf(0));
        map.put("othThrd", BigDecimal.valueOf(0));
        map.put("othScnd", BigDecimal.valueOf(0));
        chrgitms.forEach(itm -> {
            map.replace("allfeeSum", map.get("allfeeSum").add(BigDecimal.valueOf(itm.getChargeFee())));
            if (itm.getChrgitmLv().equals(ChrgitmLv.SELF_PAY.getCode())) {
                map.replace("totalThrd", map.get("totalThrd").add(BigDecimal.valueOf(itm.getChargeFee())));
            } else if (itm.getChrgitmLv().equals(ChrgitmLv.SECOND_CLASS.getCode())) {
                map.replace("totalScnd", map.get("totalScnd").add(BigDecimal.valueOf(itm.getChargeFee())));
            }
            String typeKey = itm.getMedChrgitmType();
            if (!typeKey.equals("09") && !typeKey.equals("11")) {
                map.replace("othSum", map.get("othSum").add(BigDecimal.valueOf(itm.getChargeFee())));
                if (itm.getChrgitmLv().equals(ChrgitmLv.SELF_PAY.getCode())) {
                    map.replace("othThrd", map.get("othThrd").add(BigDecimal.valueOf(itm.getChargeFee())));
                } else if (itm.getChrgitmLv().equals(ChrgitmLv.SECOND_CLASS.getCode())) {
                    map.replace("othScnd", map.get("othScnd").add(BigDecimal.valueOf(itm.getChargeFee())));
                }
            } else {
                String lvKey = typeKey + "-" + itm.getChrgitmLv();
                if (map.containsKey(typeKey)) {
                    map.replace(typeKey, map.get(typeKey).add(BigDecimal.valueOf(itm.getChargeFee())));
                } else {
                    map.put(typeKey, BigDecimal.valueOf(itm.getChargeFee()));
                }
                if (map.containsKey(lvKey)) {
                    map.replace(lvKey, map.get(lvKey).add(BigDecimal.valueOf(itm.getChargeFee())));
                } else {
                    map.put(lvKey, BigDecimal.valueOf(itm.getChargeFee()));
                }
            }

        });
        lst.setAllfeeSum(map.get("allfeeSum"));
        lst.setAllfeeThrd(map.get("totalThrd"));
        lst.setAllfeeScnd(map.get("totalScnd"));
        lst.setWestMedFeeSum(map.get("09"));
        lst.setWestMedFeeThrd(map.get("09-03"));
        lst.setWestMedFeeScnd(map.get("09-02"));
        lst.setChnsPtntSum(map.get("11"));
        lst.setChnsPtntThrd(map.get("11-03"));
        lst.setChnsPtntScnd(map.get("11-02"));
        lst.setMedsrvcSum(map.get("othSum"));
        lst.setMedsrvcThrd(map.get("othThrd"));
        lst.setMedsrvcScnd(map.get("othScnd"));
    }

    public ResultVo<List<SiMzMatnDise>> queryMzMatnDises() {
        return ResultVoUtil.success(dao.selectAllMzMatnDises());
    }

    public ResultVo<List<SetlStatisticResult>> selectSetlinfoStatistics(SetlCondition condition) {
        List<BaseSetlStatistics> baseStatistics = getBaseStatistics(condition);
        if (null == baseStatistics || baseStatistics.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }

        Map<String, String> regionMap = new HashMap<>();
        Map<String, List<BaseSetlStatistics>> admdvsSetldataMap = new HashMap<>();

        List<BaseSetlStatistics> setlListUpload = new ArrayList<>();

        baseStatistics.forEach(itm -> {
            itm.setInsutypeName(Insutype.getName(itm.getInsutype()));
            itm.setInsuplcAdmdvsName(regionCache.get(itm.getInsuplcAdmdvs()));
            String key;
            if (condition.getAdmdvsType() == 5 || condition.getAdmdvsType() == 6) {
                key = itm.getInsuplcAdmdvs();
            } else {
                key = itm.getInsuplcAdmdvs().substring(0, 4) + "00";
            }
            String admdvsName = regionMap.get(key);
            if (null == admdvsName) {
                CodeName region = dao.selectAdmdvsNameAndParentName(key);
                if (null == region) {
                    region = dao.selectAdmdvsName(key);
                }
                if (null == region) {
                    key = itm.getInsuplcAdmdvs().substring(0, 2) + "0000";
                    region = dao.selectAdmdvsNameAndParentName(key);
                }
                if (null == region) {
                    admdvsName = "未知";
                } else {
                    admdvsName = region.getCode() + region.getName();
                }
                regionMap.put(key, admdvsName);
            }
            if (admdvsSetldataMap.containsKey(admdvsName)) {
                admdvsSetldataMap.get(admdvsName).add(itm);
            } else {
                List<BaseSetlStatistics> tempList = new ArrayList<>();
                tempList.add(itm);
                admdvsSetldataMap.put(admdvsName, tempList);
            }
            itm.setMedTypeName(MedType.getName(itm.getMedType()));
            setlListUpload.add(itm);
        });

        List<SetlStatisticResult> resultList = new ArrayList<>();
        for (Map.Entry<String, List<BaseSetlStatistics>> entry : admdvsSetldataMap.entrySet()) {
            List<BaseSetlStatistics> admdvsSetldataList = entry.getValue();
            SetlStatisticResult resultItem = new SetlStatisticResult();
            resultItem.setAdmdvsName(entry.getKey());
            resultItem.setInsuplcAdmdvs(entry.getValue().get(0).getInsuplcAdmdvs().substring(0, 4) + "00");
            resultItem.setPsnSumamt(admdvsSetldataList.size());
            if (StringUtil.notBlank(condition.getInsutype())) {
                resultItem.setInsutype(condition.getInsutype());
                resultItem.setInsutypeName(Insutype.getName(condition.getInsutype()));
                resultItem.setChildKey(entry.getKey() + "-" + resultItem.getInsutypeName());
            } else {
                resultItem.setInsutypeName("-");
                resultItem.setChildKey(entry.getKey());
            }
            fillSetlStatisticResult(resultList, admdvsSetldataList, resultItem);
        }

        if (StringUtil.isBlank(condition.getInsutype())) {
            for (SetlStatisticResult resultItem : resultList) {
                Map<String, List<BaseSetlStatistics>> insutypeSetldataMap = new HashMap<>();
                String admdvsName = resultItem.getAdmdvsName();
                List<BaseSetlStatistics> admdvsSetldataList = admdvsSetldataMap.get(admdvsName);
                for (BaseSetlStatistics baseSetlStatistics : admdvsSetldataList) {
                    if (insutypeSetldataMap.containsKey(baseSetlStatistics.getInsutypeName())) {
                        insutypeSetldataMap.get(baseSetlStatistics.getInsutypeName()).add(baseSetlStatistics);
                    } else {
                        List<BaseSetlStatistics> tmpList = new ArrayList<>();
                        tmpList.add(baseSetlStatistics);
                        insutypeSetldataMap.put(baseSetlStatistics.getInsutypeName(), tmpList);
                    }
                }
                if (insutypeSetldataMap.size() == 1) {
                    resultItem.setInsutype(admdvsSetldataList.get(0).getInsutype());
                    resultItem.setInsutypeName(admdvsSetldataList.get(0).getInsutypeName());
                    continue;
                }
                List<SetlStatisticResult> children = new ArrayList<>();
                for (Map.Entry<String, List<BaseSetlStatistics>> entry : insutypeSetldataMap.entrySet()) {
                    List<BaseSetlStatistics> insutypeSetldataList = entry.getValue();
                    SetlStatisticResult result = new SetlStatisticResult();
                    result.setAdmdvsName(resultItem.getAdmdvsName());
                    result.setInsuplcAdmdvs(resultItem.getInsuplcAdmdvs());
                    result.setPsnSumamt(insutypeSetldataList.size());
                    result.setInsutype(entry.getValue().get(0).getInsutype());
                    result.setInsutypeName(entry.getValue().get(0).getInsutypeName());
                    result.setChildKey(resultItem.getAdmdvsName() + "-" + result.getInsutypeName());
                    result.setIsChildren(true);
                    fillSetlStatisticResult(children, insutypeSetldataList, result);
                }
                resultItem.setChildren(children);
            }
        }
        resultList.get(0).setShangChuanJieSuanDan(setlListUpload);
        return ResultVoUtil.success(resultList);
    }

    private List<BaseSetlStatistics> getBaseStatistics(SetlCondition condition) {
        String begntime = condition.getMonth() + "-01 00:00:00.000";
        String endtime = DateUtil.getMonthEndtime(condition.getMonth());
        String insutype = condition.getInsutype();
        if (StringUtil.isBlank(insutype)) {
            insutype = "%%";
        }
        switch (condition.getAdmdvsType()) {
            case 1:
                String pro = cfg.getHospArea().substring(0, 2) + "9900";
                return dao.selectBaseSetlStatisticsInProvinceLevel(begntime, endtime, insutype, condition.getSetlType(), pro);
            case 2:
                return dao.selectBaseSetlStatisticsInChangshaCity(begntime, endtime, insutype, condition.getSetlType());
            case 3:
                return dao.selectBaseSetlStatisticsInProvinceOtherCities(begntime, endtime, insutype, condition.getSetlType());
            case 4:
                return dao.selectBaseSetlStatisticsOutProvince(begntime, endtime, insutype, condition.getSetlType());
            case 5:
                return dao.selectBaseSetlStatisticsInChangshaCounty(begntime, endtime, insutype, condition.getSetlType());
            case 6:
                return dao.selectBaseSetlStatisticsInLiuYangCity(begntime, endtime, insutype, condition.getSetlType());
            default:
                return dao.selectBaseSetlStatisticsInAllPlaces(begntime, endtime, insutype, condition.getSetlType());
        }
    }

    private void fillSetlStatisticResult(List<SetlStatisticResult> resultList, List<BaseSetlStatistics> admdvsSetldataList, SetlStatisticResult resultItem) {
        String medfeeSumamt = "0";
        String baseMedFundpaySumamt = "0";
        String bigDssFundpaySumamt = "0";
        String clvFundpaySumamt = "0";
        String acctpaySumamt = "0";
        String othFundpaySumamt = "0";
        String fundpaySumamt = "0";
        for (BaseSetlStatistics itm : admdvsSetldataList) {
            medfeeSumamt = DecimalUtil.add(medfeeSumamt, itm.getMedfeeSumamt());
            baseMedFundpaySumamt = DecimalUtil.add(baseMedFundpaySumamt, itm.getHifpPay());
            bigDssFundpaySumamt = DecimalUtil.add(bigDssFundpaySumamt, itm.getHifmiPay());
            clvFundpaySumamt = DecimalUtil.add(clvFundpaySumamt, itm.getCvlservPay());
            acctpaySumamt = DecimalUtil.add(acctpaySumamt, itm.getAcctPay());
            fundpaySumamt = DecimalUtil.add(fundpaySumamt, itm.getFundPaySumamt(), itm.getAcctPay());
            String othpay = DecimalUtil.minusLink(itm.getFundPaySumamt(), itm.getHifpPay(), itm.getHifmiPay(), itm.getCvlservPay());
            othFundpaySumamt = DecimalUtil.add(othFundpaySumamt, othpay);
        }
        resultItem.setMedfeeSumamt(medfeeSumamt);
        resultItem.setBaseMedFundpaySumamt(baseMedFundpaySumamt);
        resultItem.setBigDssFundpaySumamt(bigDssFundpaySumamt);
        resultItem.setClvFundpaySumamt(clvFundpaySumamt);
        resultItem.setAcctpaySumamt(acctpaySumamt);
        resultItem.setOthFundpaySumamt(othFundpaySumamt);
        resultItem.setFundpaySumamt(fundpaySumamt);
        resultList.add(resultItem);
    }

    public ResultVo<List<SiSetlinfo>> selectSetldetailStatistics(SetlCondition condition) {
        String begntime = condition.getMonth() + "-01 00:00:00.000";
        String endtime = DateUtil.getMonthEndtime(condition.getMonth());
        String admdvsStatement = getAdmdvsStatement(condition.getAdmdvsType());
        String insutype = condition.getInsutype();
        if (StringUtil.isBlank(insutype)) {
            insutype = "%%";
        }
        List<SiSetlinfo> list = setlinfoDao.selectMyList(condition.getSetlType(), insutype, admdvsStatement, begntime, endtime);
        list.forEach(item -> {
            if (null != item.getHospPartAmt()) {
                item.setFundPaySumamt(DecimalUtil.minusDouble(item.getFundPaySumamt(), item.getHospPartAmt()));
            }
            item.setInsuplcAdmdvsName(regionCache.get(item.getInsuplcAdmdvs()));
            FilterUtil.filterCodeToName(item);
        });
        return ResultVoUtil.success(list);
    }

    private String getAdmdvsStatement(int admdvstype) {
        switch (admdvstype) {
            case 1:
                return " and insuplc_admdvs='439900' ";
            case 2:
                return " and insuplc_admdvs like '4301%' and  insuplc_admdvs not in ('430121','430181') ";
            case 3:
                return " and insuplc_admdvs like '43%' and insuplc_admdvs not like '4301%' ";
            case 4:
                return " and insuplc_admdvs not like '43%' ";
            case 5:
                return " and insuplc_admdvs='430121' ";
            case 6:
                return " and insuplc_admdvs='430181' ";
            default:
                return "";
        }
    }

    public ResultVo<List<ZyActpatient>> weiJieSuanZaiYuanHuanZhe(String patNo, String startTime, String endTime, String name, String certno) {
        List<ZyActpatient> actpatients = dao.zaiYuanHuanZheXinXi(patNo, startTime, endTime, StringUtil.isContainChinese(name), certno);
        Map<String, String> insuplcAdmdvs = new HashMap<>();
        for (ZyActpatient actpatient : actpatients) {
            if (StringUtil.isBlank(actpatient.getInsuplcAdmdvsName())) {
                String key = actpatient.getInsuplcAdmdvs().substring(0, 4) + "00";
                if (insuplcAdmdvs.containsKey(key)) {
                    actpatient.setInsuplcAdmdvsName(insuplcAdmdvs.get(key));
                } else {
                    String insuplcAdmdvsName = regionCache.get(key);
                    insuplcAdmdvs.put(key, insuplcAdmdvsName);
                    actpatient.setInsuplcAdmdvsName(insuplcAdmdvsName);
                }
            }
        }
        return ResultVoUtil.success(actpatients);
    }

    public ResultVo<String> checkRegisterDate(String patNo, Integer times) {
        if (dao.selectLedgerCount(patNo, times) == 1) {
            return ResultVoUtil.success();
        }
        Date ledgerAccountDate = dao.selectMaxLedgerAccountDate(patNo, times);
        if (null == ledgerAccountDate) {
            return ResultVoUtil.success();
        }
        Date registerDate = dao.selectRegisterDate(patNo);
        if (null == registerDate) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保登记日期不能为空。");
        }
        Calendar ledgerCalendar = Calendar.getInstance();
        ledgerCalendar.setTime(ledgerAccountDate);
        Calendar registerCalendar = Calendar.getInstance();
        registerCalendar.setTime(registerDate);
        if (registerCalendar.after(ledgerCalendar)) {
            return ResultVoUtil.success();
        }
        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, String.format("医保登记日期【%s】不能小于断账日期【%s】，请修改。", DateUtil.formatDatetime(registerDate), DateUtil.formatDatetime(ledgerAccountDate)));
    }

    public void saveCumInfo(SiSetlinfo setlinfo) {
        new SaveCumInfo(dao, setlinfo).start();
    }

    class SaveCumInfo extends Thread {
        private final SiQueryDao dao;
        private final SiSetlinfo setlinfo;

        SaveCumInfo (SiQueryDao dao, SiSetlinfo setlinfo) {
            this.dao = dao;
            this.setlinfo = setlinfo;
        }

        @Override
        public void run() {
            if (dao.selectCumInfoCount(setlinfo.getSetlId()) == 0) {
                CuminfoInYear cuminfo = getYearCuminfo(setlinfo.getSetlId(), setlinfo.getPsnNo(), setlinfo.getInsuplcAdmdvs());
                if (Objects.equals(cuminfo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
                    cuminfo.setSetlId(setlinfo.getSetlId());
                    dao.insertCumInfo(cuminfo);
                }
            }
        }
    }

}
