package thyyxxk.webserver.service.inpatient.casefrontsheet.tcm;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.constants.Capacity;
import thyyxxk.webserver.entity.casefrontsheet.tcmsheet.TcmFrontSheetDisdiag;
import thyyxxk.webserver.entity.casefrontsheet.tcmsheet.TcmFrontSheetMain;
import thyyxxk.webserver.entity.casefrontsheet.tcmsheet.TcmFrontSheetSurgery;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.utils.*;

import java.util.*;

@Slf4j
@Service
public class TcmSheetVerifyService {

    public List<CodeName> verify(TcmFrontSheetMain info) {
        List<CodeName> array = new ArrayList<>();
        if (StringUtil.isBlank(info.getPayWay())) {
            array.add(new CodeName("payWay", "医疗付费方式不能为空！"));
        }
        if (StringUtil.invalidValue(info.getName())) {
            array.add(new CodeName("name", "患者姓名不能为空！"));
        }
        if (StringUtil.invalidValue(info.getGender())) {
            array.add(new CodeName("gender", "患者性别不能为空！"));
        }

        if (null == info.getBirthYear() || null == info.getBirthMonth() || null == info.getBirthDay()) {
            array.add(new CodeName("birthDate", "患者出生日期不能为空！"));
        }
        if (null == info.getAge() && null == info.getInfAge()) {
            array.add(new CodeName("age","患者年龄不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCountry())) {
            array.add(new CodeName("country","患者国籍不能为空！"));
        }
        if (StringUtil.invalidBirthPlace(info.getBpProvince()) ||
                StringUtil.invalidValue(info.getBpCity()) ||
                StringUtil.invalidValue(info.getBpCounty())) {
            array.add(new CodeName("birthPlace","患者出生地不能为空！"));
        }
        if (StringUtil.invalidValue(info.getNpProvince()) ||
                StringUtil.invalidValue(info.getNpCity()) ||
                StringUtil.invalidValue(info.getNpCounty())) {
            array.add(new CodeName("nativePlace","患者籍贯不能为空！"));
        }
        if (StringUtil.invalidValue(info.getNation())) {
            array.add(new CodeName("nation","患者民族不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCertType())) {
            array.add(new CodeName("certType", "患者身份证件类型不能为空！"));
        }
        if (StringUtil.isBlank(info.getCertNo())) {
            array.add(new CodeName("certNo", "患者身份证件号码不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCertNo()) && StringUtil.isBlank(info.getNoCertReason())) {
            array.add(new CodeName("noCertReason", "患者没有身份证件号码时，身份证件不详的具体原因不能为空！"));
        }
        if (Objects.equals(info.getNoCertReason(), "9") &&
                StringUtil.invalidValue(info.getNoCertReasonInput())) {
            array.add(new CodeName("noCertReasonInput", "身份证件不详的具体原因为其他时，补充原因不能为空！"));
        }

        if (StringUtil.invalidValue(info.getOccupation())) {
            array.add(new CodeName("occupation","患者职业不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMarriage())) {
            array.add(new CodeName("marriage","患者婚姻状况不能为空！"));
        }
        if (StringUtil.invalidValue(info.getLpProvince()) ||
            StringUtil.invalidValue(info.getLpCity()) ||
            StringUtil.invalidValue(info.getLpCounty()) ||
            StringUtil.invalidValue(info.getLpSup())) {
            array.add(new CodeName("livePlace","患者现住址不能为空！"));
        }
        if (StringUtil.invalidValue(info.getPhone())) {
            array.add(new CodeName("phone","患者电话号码不能为空！"));
        }
        if (StringUtil.invalidValue(info.getLpZipCode())) {
            array.add(new CodeName("lpZipCode","患者现住址邮编不能为空！"));
        }

        if (StringUtil.invalidValue(info.getHpProvince()) ||
                StringUtil.invalidValue(info.getHpCity()) ||
                StringUtil.invalidValue(info.getHpCounty()) ||
                StringUtil.invalidValue(info.getHpSup())) {
            array.add(new CodeName("hkPlace","患者户口地址不能为空！"));
        }
        if (StringUtil.invalidValue(info.getHpZipCode())) {
            array.add(new CodeName("hpZipCode","患者户口地址邮编不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUnitName())) {
            array.add(new CodeName("unitName","患者工作单位不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUnitPlace())) {
            array.add(new CodeName("unitPlace","患者工作单位地址不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUnitPhone())) {
            array.add(new CodeName("unitPhone","患者单位电话不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUnitZipCode())) {
            array.add(new CodeName("unitZipCode", "患者工作单位邮编不能为空！"));
        }
        if (StringUtil.invalidValue(info.getConName())) {
            array.add(new CodeName("conName","患者联系人姓名不能为空！"));
        }
        if (StringUtil.invalidValue(info.getConRel())) {
            array.add(new CodeName("conRel","患者联系人关系不能为空！"));
        }
        if (StringUtil.invalidValue(info.getConAddr())) {
            array.add(new CodeName("conAddr","患者联系人地址不能为空！"));
        }
        if (StringUtil.invalidValue(info.getConPhone())) {
            array.add(new CodeName("conPhone","患者联系人电话不能为空！"));
        }
        if (StringUtil.invalidValue(info.getZyAdmWay())) {
            array.add(new CodeName("zyAdmWay","患者入院途径不能为空！"));
        }
        if (StringUtil.invalidValue(info.getTreatWay())) {
            array.add(new CodeName("treatWay", "患者治疗类别不为能空！"));
        }
        if (null == info.getAdmissYear() || null == info.getAdmissMonth()
                || null == info.getAdmissDay() || null == info.getAdmissHour()) {
            array.add(new CodeName("admissDate","患者入院时间不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissDept())) {
            array.add(new CodeName("admissDept","患者入院科别不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissWard())) {
            array.add(new CodeName("admissWard","患者入院病房不能为空！"));
        }
        if (null == info.getDismissYear() || null == info.getDismissMonth()
                || null == info.getDismissDay() || null == info.getDismissHour()) {
            array.add(new CodeName("dismissDate","患者出院时间不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDismissDept())) {
            array.add(new CodeName("dismissDept","患者出院科别不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDismissWard())) {
            array.add(new CodeName("dismissWard","患者出院病房不能为空！"));
        }
        if (null == info.getInHospDays()) {
            array.add(new CodeName("inHospDays","患者住院天数不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMzTcmDiagCode())) {
            array.add(new CodeName("mzTcmDiag","门急诊中医诊断不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMzWstDiagCode())) {
            array.add(new CodeName("mzWstDiag","门急诊西医诊断不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUsePathway())) {
            array.add(new CodeName("usePathway", "实施临床路径不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUseTcmPrep())) {
            array.add(new CodeName("useTcmPrep", "使用医疗机构中药制剂不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUseTcmEqp())) {
            array.add(new CodeName("useTcmEqp", "使用中医诊疗设备不能为空！"));
        }
        if (StringUtil.invalidValue(info.getUseTcmTech())) {
            array.add(new CodeName("useTcmTech", "使用中医诊疗技术不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDiaNursing())) {
            array.add(new CodeName("diaNursing", "辨证施护不能为空！"));
        }

        TcmFrontSheetDisdiag disdiag = info.getDisdiagList().get(0);
        if (StringUtil.isBlank(disdiag.getTcmCode())) {
            array.add(new CodeName("mainTcmDiag1","患者中医主要疾病不能为空！"));
        }
        if (StringUtil.invalidValue(disdiag.getTcmAdmStatus())) {
            array.add(new CodeName("mainTcmAdmStatus1","患者中医主要疾病入院病情不能为空！"));
        }

        TcmFrontSheetDisdiag zh = info.getDisdiagList().get(1);
        if (StringUtil.isBlank(zh.getTcmCode())) {
            array.add(new CodeName("mainTcmDiag2","患者中医主要证候不能为空！"));
        }
        if (StringUtil.invalidValue(zh.getTcmAdmStatus())) {
            array.add(new CodeName("mainTcmAdmStatus2","患者中医主要证候入院病情不能为空！"));
        }

        if (StringUtil.isBlank(disdiag.getWstCode())) {
            array.add(new CodeName("mainWstDiag","患者西医主要诊断不能为空！"));
        }
        if (StringUtil.invalidValue(disdiag.getWstAdmStatus())) {
            array.add(new CodeName("mainWstAdmStatus","患者西医主要诊断入院病情不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAllergy())) {
            array.add(new CodeName("allergy","患者有无药物过敏不能为空！"));
        }
        if (Objects.equals(info.getAllergy(), "2") && StringUtil.invalidValue(info.getAllergyMed())) {
            array.add(new CodeName("allergyMed","患者有药物过敏时，过敏药物名称不能为空！"));
        }
        if (StringUtil.invalidValue(info.getZyDismissWay())) {
            array.add(new CodeName("zyDismissWay","患者离院方式不能为空！"));
        }
        if (Objects.equals(info.getZyDismissWay(), "5") && StringUtil.isBlank(info.getAutopsy())) {
            array.add(new CodeName("autopsy", "离院方式为死亡时，尸检不能为空！"));
        }
        if (StringUtil.notBlank(info.getAutopsy()) && !Objects.equals(info.getZyDismissWay(), "5")) {
            array.add(new CodeName("zyDismissWay","尸检不为空时，需要离院方式为死亡！"));
        }
        if (StringUtil.invalidValue(info.getAdmissAgain())) {
            array.add(new CodeName("admissAgain","患者是否有出院31天内再住院计划不能为空！"));
        }
        if (Objects.equals(info.getAdmissAgain(), "2") &&
                StringUtil.invalidValue(info.getAdmissAgainPurpose())) {
            array.add(new CodeName("admissAgainPurpose","患者有出院31天内再住院计划，再住院目的不能为空！"));
        }
        if (StringUtil.invalidValue(info.getKzy())) {
            array.add(new CodeName("kzyName","科主任不能为空！"));
        }
        if (StringUtil.invalidValue(info.getZyfzyDoc())) {
            array.add(new CodeName("zyfzyDocName","主任（副主任）医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMainDoc())) {
            array.add(new CodeName("mainDocName","主治医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmDoc())) {
            array.add(new CodeName("admDocName","住院医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDutyNur())) {
            array.add(new CodeName("dutyNurName","责任护士不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCoder())) {
            array.add(new CodeName("coderName","编码员不能为空！"));
        }
        if (zipCodeLengthWrong(info.getLpZipCode())) {
            array.add(new CodeName("lpZipCode","现住址邮编长度错误！"));
        }
        if (zipCodeLengthWrong(info.getHpZipCode())) {
            array.add(new CodeName("hpZipCode","户口地址邮编长度错误！"));
        }
        if (zipCodeLengthWrong(info.getUnitZipCode())) {
            array.add(new CodeName("unitZipCode","工作地址邮编错误！"));
        }
        if (phoneLengthWrong(info.getPhone())) {
            array.add(new CodeName("phone","患者电话号码长度错误！"));
        }
        if (phoneLengthWrong(info.getConPhone())) {
            array.add(new CodeName("conPhone","联系人电话号码长度错误！"));
        }
        if (phoneLengthWrong(info.getUnitPhone())) {
            array.add(new CodeName("unitPhone","工作单位电话长度错误！"));
        }

        Calendar birth = Calendar.getInstance();
        birth.set(Calendar.YEAR, info.getBirthYear());
        birth.set(Calendar.MONTH, info.getBirthMonth());
        birth.set(Calendar.DAY_OF_MONTH, info.getBirthDay());

        Calendar adm = Calendar.getInstance();
        adm.set(Calendar.YEAR, info.getAdmissYear());
        adm.set(Calendar.MONTH, info.getAdmissMonth());
        adm.set(Calendar.DAY_OF_MONTH, info.getAdmissDay());

        if (birth.after(adm)) {
            array.add(new CodeName("birthDate","出生时间不能晚于入院时间！"));
        }

        Calendar dis = null;
        if (null != info.getDismissYear() && null != info.getDismissMonth() && null != info.getDismissDay()) {
            dis =  Calendar.getInstance();
            dis.set(Calendar.YEAR, info.getDismissYear());
            dis.set(Calendar.MONTH, info.getDismissMonth());
            dis.set(Calendar.DAY_OF_MONTH, info.getDismissDay());
            if (adm.after(dis)) {
                array.add(new CodeName("dismissDate","出院时间不能早于入院时间！"));
            }
        }

        if (null != info.getNbAge() && info.getNbAge() <= 28) {
            if (null == info.getNbWeight1()) {
                array.add(new CodeName("nbWeight1","请填写新生儿出生体重！"));
            }
            if (null == info.getNbAdmWeight()) {
                array.add(new CodeName("nbAdmWeight","请填写新生儿入院体重！"));
            }

            if (null != info.getNbWeight1() && info.getNbWeight1() < 1000) {
                array.add(new CodeName("nbWeight1","请填写合理的新生儿出生体重（不得少于1000g）！"));
            }
            if (null != info.getNbAdmWeight() && info.getNbAdmWeight() < 1000) {
                array.add(new CodeName("newBornAdmissWeight","请填写合理的新生儿入院体重（不得少于1000g）！"));
            }
        }
        return connectedVerify(array, info, adm, dis);
    }

    private List<CodeName> connectedVerify(List<CodeName> array, TcmFrontSheetMain info,
                                           Calendar adm, Calendar dis) {
        boolean hasAnaesthesia = false;
        boolean hasAnaesthesiaor = false;
        for (TcmFrontSheetSurgery surgery : info.getSurgeryList()) {
            checkSurgery(array, surgery);
            if (StringUtil.notBlank(surgery.getAnaesthesia())) {
                hasAnaesthesia = true;
            }
            if (StringUtil.notBlank(surgery.getAnestorCode())) {
                hasAnaesthesiaor = true;
            }
        }

        if (DecimalUtil.biggerThanZero(info.getSszlFee())) {
            if (StringUtil.isBlank(info.getSurgeryList().get(0).getCode())) {
                array.add(new CodeName("surgeryTable", "手术治疗费>0时，手术列表不能为空！"));
            }
        }

        if (DecimalUtil.biggerThanZero(info.getAnesthetizeFee())) {
            if (!hasAnaesthesia) {
                array.add(new CodeName("surgeryMain", "患者有麻醉费，麻醉方式不能为空！"));
            }
            if (!hasAnaesthesiaor) {
                array.add(new CodeName("surgeryMain", "患者有麻醉费，麻醉医师不能为空！"));
            }
        }

        if (hasDuplicateDiag(info.getDisdiagList())) {
            array.add(new CodeName("diagTable","出院诊断不能存在相同的诊断编码！"));
        }
        if (hasSameSurgeryInOneDay(info.getSurgeryList())) {
            array.add(new CodeName("surgeryTable","同一天不能有相同的手术！"));
        }
        if (surgeryDateWrong(info.getSurgeryList(), adm, dis)) {
            array.add(new CodeName("surgeryTable","手术时间必须在入院时间24小时之前和出院时间之间！"));
        }
        if (info.getRescueTimes() < 0) {
            array.add(new CodeName("rescueTimes","抢救次数不能为负数！"));
        }
        if (info.getRescueTimes() < info.getRescueSuccessTimes()) {
            array.add(new CodeName("rescueSuccessTimes","抢救成功次数不能大于抢救次数！"));
        }
        if (info.getRescueTimes() - info.getRescueSuccessTimes() > 1) {
            array.add(new CodeName("rescueSuccessTimes","抢救成功次数不能少于抢救次数两次！"));
        }
        return array;
    }


    private void checkSurgery(List<CodeName> array, TcmFrontSheetSurgery surgery) {
        if (StringUtil.isBlank(surgery.getName())) {
            return;
        }
        if (StringUtil.isBlank(surgery.getOperCode())) {
            array.add(new CodeName("surgeryTable","手术" + surgery.getSortNo() + "，术者不能为空！"));
        }
    }

    private boolean hasDuplicateDiag(List<TcmFrontSheetDisdiag> disdiags) {
        Map<String, String> map = new HashMap<>(Capacity.DEFAULT);
        for (TcmFrontSheetDisdiag diag : disdiags) {
            if (StringUtil.validValue(diag.getTcmCode())) {
                if (map.containsKey(diag.getTcmCode())) {
                    return true;
                }
                map.put(diag.getTcmCode(), diag.getTcmName());
            }
            if (StringUtil.validValue(diag.getWstCode())) {
                if (map.containsKey(diag.getWstCode())) {
                    return true;
                }
                map.put(diag.getWstCode(), diag.getWstName());
            }
        }
        return false;
    }

    private boolean hasSameSurgeryInOneDay(List<TcmFrontSheetSurgery> surgeries) {
        Map<String, String> map = new HashMap<>(Capacity.DEFAULT);
        for (TcmFrontSheetSurgery surgery : surgeries) {
            if (StringUtil.validValue(surgery.getCode())) {
                if (map.containsKey(surgery.getCode() + DateUtil.formatDatetime(surgery.getDate(), "yyyy-MM-dd HH:mm:ss"))) {
                    return true;
                }
                map.put(surgery.getCode() + DateUtil.formatDatetime(surgery.getDate(), "yyyy-MM-dd HH:mm:ss"), surgery.getCode());
            }
        }
        return false;
    }

    private boolean zipCodeLengthWrong(String zipCode) {
        return StringUtil.notBlank(zipCode) && zipCode.length() != 6;
    }

    private boolean surgeryDateWrong(List<TcmFrontSheetSurgery> surgeries, Calendar adm, Calendar dis) {
        if (null == adm || null == dis) {
            return false;
        }
        for (TcmFrontSheetSurgery item : surgeries) {
            if (StringUtil.notBlank(item.getCode()) && null == item.getDate()) {
                return true;
            }
            if (item.getDate().before(adm.getTime()) || item.getDate().after(dis.getTime())) {
                return true;
            }
        }
        return false;
    }

    private boolean phoneLengthWrong(String phone) {
        if (StringUtil.isBlank(phone)) {
            return false;
        }
        return phone.length() != 11 && phone.length() != 12 && phone.length() != 8;
    }
}
