package com.ywt.outpatient.core.utils;


import com.google.gson.JsonObject;
import com.ywt.biz.common.enums.OrderTypeEnum;
import com.ywt.biz.common.enums.TerminalEnum;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.outpatient.api.checkIn.CheckInConstants;
import com.ywt.outpatient.api.union_reg.HospitalCustomInfo;
import com.ywt.outpatient.core.Constant;
import com.ywt.outpatient.core.Constants;
import com.ywt.outpatient.core.WebAppContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public final class BizUtil {

    private static String payCode4NfyybyfyTest;

    @Value("${test.paycode4nfyybyfy:}")
    public void setPayCode4NfyybyfyTest(String pc) {
        BizUtil.payCode4NfyybyfyTest = pc;
    }

    /**
     * 获取对应的患者客户端terminal值
     * <p>
     * 根据当前客户端，判断是否是医生版，若是则返回与该医生版对应的患者客户端terminal值，否则返回0
     *
     * @param currentTerminal 当前客户端terminal值
     * @return 对应的患者客户端terminal值, 0: 找不到对应值
     */
    public static int getAssociatedPatientTerminalValue(int currentTerminal) {
        if (!TerminalEnum.isDoctorTerminal(currentTerminal)) return 0;
        switch (TerminalEnum.valueOf(currentTerminal)) {
            case DoctorWxOfficial:
                return TerminalEnum.PatientWxOfficial.getValue();
            case TAI_HE_INTERNET_HOSPITAL_DOCTOR_WX_OFFICIAL:
                return TerminalEnum.TAI_HE_INTERNET_HOSPITAL_PATIENT_WX_OFFICIAL.getValue();
            default:
                return 0;
        }
    }

    /**
     * 获取对应的医生客户端terminal值
     * <p>
     * 根据当前客户端，判断是否是患者版，若是则返回与该医生版对应的医生客户端terminal值，否则返回0
     *
     * @param currentTerminal 当前客户端terminal值
     * @return 对应的医生客户端terminal值, 0: 找不到对应值
     */
    public static int getAssociatedDoctorTerminalValue(int currentTerminal) {
        if (!TerminalEnum.isPatientTerminal(currentTerminal)) return 0;
        switch (TerminalEnum.valueOf(currentTerminal)) {
            case PatientWxOfficial:
            case PatientWxApp:
                return TerminalEnum.DoctorWxOfficial.getValue();
            case TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM:
            case TAI_HE_INTERNET_HOSPITAL_PATIENT_WX_OFFICIAL:
                return TerminalEnum.TAI_HE_INTERNET_HOSPITAL_DOCTOR_WX_OFFICIAL.getValue();
            default:
                return 0;
        }
    }

    /**
     * 获取对应的患者客户端terminal
     * <p>
     * 根据当前客户端，判断是否是医生版，若是则返回与该医生版对应的患者客户端terminal值，否则返回0
     *
     * @param currentTerminal 当前客户端terminal值
     * @return 对应的患者客户端terminal
     */
    public static TerminalEnum getAssociatedPatientTerminal(int currentTerminal) {
        if (!TerminalEnum.isDoctorTerminal(currentTerminal)) return TerminalEnum.UNKNOWN;
        switch (TerminalEnum.valueOf(currentTerminal)) {
            case DoctorWxOfficial:
                return TerminalEnum.PatientWxOfficial;
            case TAI_HE_INTERNET_HOSPITAL_DOCTOR_WX_OFFICIAL:
                return TerminalEnum.TAI_HE_INTERNET_HOSPITAL_PATIENT_WX_OFFICIAL;
            default:
                return TerminalEnum.UNKNOWN;
        }
    }

    /**
     * 生成模板消息跳转小程序所需的参数
     *
     * @param appId    跳转的小程序appId
     * @param pagePath 页面
     * @return param string
     */
    public static String getMiniProgramParam(String appId, String pagePath) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("appid", appId);
        jsonObject.addProperty("pagepath", pagePath);
        return jsonObject.toString();
    }

    /**
     * 对医学界文章内容根据字数进行截取
     *
     * @param rawText  原始文本
     * @param splitLen 截取长度
     * @return 截取后的文本
     */
    public static String getArticleContentDigest(String rawText, int splitLen) {
        rawText = removeHTMLTags(rawText);
        if (StringHelper.isNullOrEmpty(rawText)) return "";
        if (rawText.length() < splitLen) return rawText;
        return rawText.substring(0, splitLen);
    }

    /**
     * 对医学界文章内容根据百分比进行截取
     *
     * @param rawText 原始文本
     * @param percent 截取的百分比，range 0.0F~1.0F
     * @return 截取后的文本
     */
    public static String getArticleContentDigest(String rawText, float percent) {
        rawText = removeHTMLTags(rawText);
        if (StringHelper.isNullOrEmpty(rawText)) return "";
        if (percent < 0) percent = 0F;
        if (percent > 1F) percent = 1F;
        int splitLen = (int) Math.floor(rawText.length() * percent);
        if (rawText.length() < splitLen) return rawText;
        return rawText.substring(0, splitLen);
    }

    private static String removeHTMLTags(String htmlStr) {
        String RegExScript = "<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
        String RegExStyle = "<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
        String RegExHtml = "<[^>]+>"; //定义HTML标签的正则表达式
        String regexNBSP = "&nbsp;";

        Pattern pScript = Pattern.compile(RegExScript, Pattern.CASE_INSENSITIVE);
        Matcher mScript = pScript.matcher(htmlStr);
        htmlStr = mScript.replaceAll(""); //过滤script标签

        Pattern pStyle = Pattern.compile(RegExStyle, Pattern.CASE_INSENSITIVE);
        Matcher mStyle = pStyle.matcher(htmlStr);
        htmlStr = mStyle.replaceAll(""); //过滤style标签

        Pattern pHtml = Pattern.compile(RegExHtml, Pattern.CASE_INSENSITIVE);
        Matcher mHtml = pHtml.matcher(htmlStr);
        htmlStr = mHtml.replaceAll(""); //过滤html标签

        Pattern pNbsp = Pattern.compile(regexNBSP, Pattern.CASE_INSENSITIVE);
        Matcher mNbsp = pNbsp.matcher(htmlStr);
        htmlStr = mNbsp.replaceAll(" ");

        return htmlStr.trim(); //返回文本字符串
    }

    public static boolean containsEmoji(String source) {
        return Pattern.compile("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]").matcher(source).find();
    }

    public static int getIntFromMapSafely(Map<String, Object> map, String key, int defaultValue) {
        return map == null ? defaultValue : Checker.getIntegerValue((Integer) map.getOrDefault(key, defaultValue), defaultValue);
    }

    public static int getIntFromMapSafely(Map<String, Object> map, String key) {
        return getIntFromMapSafely(map, key, 0);
    }

    public static String getStringFromMapSafely(Map<String, Object> map, String key, String defaultValue) {
        return map == null ? defaultValue : Checker.getStringValue((String) map.getOrDefault(key, defaultValue), defaultValue);
    }

    public static String getStringFromMapSafely(Map<String, Object> map, String key) {
        return getStringFromMapSafely(map, key, "");
    }

    public static boolean endsWithIgnoreCase(String str, String suffix) {
        int suffixLength = suffix.length();
        return str.regionMatches(true, str.length() - suffixLength, suffix, 0, suffixLength);
    }

    /**
     * 根据 hospitalId 返回 hospital name, 不查询数据库，直接读取 {@link Constants}
     *
     * @param hospitalId 医院 id
     * @return 医院名称
     */
    public static String getHospitalNameByIdSimply(int hospitalId) {
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
                return Constants.TAIHE_HOSPITAL_NAME;
            case Constants.NFYYBYFY_HOSPITAL_ID:
                return Constants.NFYYBYFY_HOSPITAL_NAME;
            default:
                return "";
        }
    }

    /**
     * 根据终端号返回对应的医院 id，目前支持太和公众号、南方医院白云分院小程序
     * <p/>
     * TODO: {@link TerminalEnum#DOCTOR_MINI_PROGRAM}, {@link TerminalEnum#PRESCRIPTION_SYSTEM_PC} 的处理？根据医生进行业务的医院决定
     *
     * @param terminalId 终端号
     * @return 医院 id
     */
    public static int getHospitalIdByTerminalId(int terminalId) {
        switch (TerminalEnum.valueOf(terminalId)) {
            case NFYYBYFY_WXAPP:
            case NFYYBYFY_DOC_WX_OFFICIAL:
            case NFYYBYFY_WX_OFFICIAL:
            case NFYYBYFY_ALIPAY_MP:
                return Constant.NFYYBYFY_HOSPITAL_ID;
            case TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM:
            case TAI_HE_INTERNET_HOSPITAL_PATIENT_WX_OFFICIAL:
            case TAI_HE_INTERNET_HOSPITAL_DOCTOR_WX_OFFICIAL:
            case TaiheWxOfficial:
            case DOCTOR_MINI_PROGRAM:
                return Constant.TAIHE_HOSPITAL_ID;
            default:
                return 0;
        }
    }


    /**
     * 根据医院 id 获取对应医院的支付代码，目前只支持太和和白云分院
     *
     * @param hospitalId 医院 id
     * @return 支付代码
     */
    public static String getHospPayCodeByHospId(int hospitalId) {
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
                return Constants.TAIHE_PAY_CODE;
            case Constants.NFYYBYFY_HOSPITAL_ID:
                if (!StringHelper.isNullOrEmpty(payCode4NfyybyfyTest)) return payCode4NfyybyfyTest;
                return Constants.NFYYBYFY_PAY_CODE;
            default:
                return "";
        }
    }

    /**
     * 根据医院 id 和终端获取对应医院的支付代码，目前只支持太和和白云分院，支持支付宝小程序和微信小程序
     *
     * @param hospitalId 医院 id
     * @return 支付代码
     */
    public static String getHospPayCodeByHospIdAndTerminal(int hospitalId, int terminal) {
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
                if (isAlipayMp(terminal)) return Constants.TH_PAY_CODE_ALIPAY;
                return Constants.TAIHE_PAY_CODE;
            case Constants.NFYYBYFY_HOSPITAL_ID:
                if (isAlipayMp(terminal)) return Constants.NFYYBYFY_PAY_CODE_ALIPAY;
                if (!StringHelper.isNullOrEmpty(payCode4NfyybyfyTest)) return payCode4NfyybyfyTest;
                return Constants.NFYYBYFY_PAY_CODE;
            default:
                return "";
        }
    }

    /**
     * 根据终端判断是否支付宝小程序
     * @param terminal 终端号
     * @return 是否支付宝小程序
     */
    public static boolean isAlipayMp(int terminal) {
        return TerminalEnum.valueOf(terminal) == TerminalEnum.NFYYBYFY_ALIPAY_MP || TerminalEnum.valueOf(terminal) == TerminalEnum.TH_ALIPAY_MP;
    }

    /**
     * 根据医院 id 获取对应公众号的 terminalId，可用来发送微信通知
     * 目前只支持太和、白云分院
     *
     * @param hospitalId 医院 id
     * @return 对应公众号终端 id
     */
    public static int getGZHTerminalIdByHospitalId(int hospitalId) {
        switch (hospitalId) {
            case Constants.TAIHE_HOSPITAL_ID:
                return TerminalEnum.TaiheWxOfficial.getValue();
            case Constants.NFYYBYFY_HOSPITAL_ID:
                return TerminalEnum.NFYYBYFY_WX_OFFICIAL.getValue();
            default:
                return TerminalEnum.UNKNOWN.getValue();
        }
    }

    public static boolean isNfyybyfyTerminal(int terminal) {
        TerminalEnum te = TerminalEnum.valueOf(terminal);
        return te.equals(TerminalEnum.NFYYBYFY_WX_OFFICIAL) || te.equals(TerminalEnum.NFYYBYFY_WXAPP) || te.equals(TerminalEnum.NFYYBYFY_DOC_WX_OFFICIAL);
    }

    public static String formatIntWithLeadingZero(int num, int digit) {
        if (digit < 1) return "";
        if (num <= 0) return "0000";
        if (num > Math.pow(10, (digit - 1))) {
            return String.valueOf(num);
        }
        StringBuilder sb = new StringBuilder();
        for (int i = digit; i > 0; i--) {
            if (num / (int) (Math.pow(10, (i - 1))) == 0) {
                sb.append("0");
            }
        }
        return sb.append(num).toString();
    }

    /**
     * 根据医院 id 获取对应医院的支付代码，医院目前只支持太和和白云分院，支付类型支持病案邮寄
     *
     * @param hospitalId 医院 id
     * @param orderType  订单类型 {@link OrderTypeEnum}
     * @return 支付代码
     */
    public static String getHospPayCodeByHospIdAndOrderType(int hospitalId, int orderType) {
        if (hospitalId == Constants.TAIHE_HOSPITAL_ID) {
            if (orderType == OrderTypeEnum.MedicalRecordMailing.getValue()) {
                return Constants.TAIHE_PAY_CODE_MP;
            }
            return Constants.TAIHE_PAY_CODE;
        }
        if (hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
            if (orderType == OrderTypeEnum.MedicalRecordMailing.getValue()) {
                return Constants.NFYYBYFY_PAY_CODE;
            }
            if (!StringHelper.isNullOrEmpty(payCode4NfyybyfyTest)) {
                return payCode4NfyybyfyTest;
            }
            return Constants.NFYYBYFY_PAY_CODE;
        }
        return "";
    }

    public static int getCurrentTerminalWrapped() {
//        return TerminalEnum.NFYYBYFY_WXAPP.getValue();
//        return TerminalEnum.TaiheWxOfficial.getValue();
        return WebAppContext.current().getTerminal();
    }

    /**
     * 根据医院 id 获取对应的互联网科室 id，目前只支持太和分院
     *
     * @param hospitalId 医院 id
     * @return 对应的互联网科室代号
     */
    public static List getNetDeptCodeListByHospitalId(int hospitalId) {
        List<String> list = new ArrayList<>();
        switch (hospitalId) {
            case Constant.TAIHE_HOSPITAL_ID:
                list.add(Constant.TAIHE_NET_DEPT_CODE);
//                list.add(ConstantDef.TAIHE_NET_DEPT_CODE_NIGHT_DIAGNOSIS);
                return list;
            case Constant.NFYYBYFY_HOSPITAL_ID:
                list.add(Constant.TAIHE_NET_DEPT_CODE);
                return list;
            default:
                return list;
        }
    }


    public static String getNBitsAsterisk(int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append("*");
        }
        return sb.toString();
    }

    /**
     * 字符串脱敏，指定保留前后 resBit 位明文显示，剩余字符串以`*`号显示。若字符串长度小于等于 2*resBit，则全部明文显示
     *
     * @param s                   待处理字符串
     * @param unmaskedLeadingBits 前缀不脱敏位数，0 表示开头开始脱敏
     * @param unmaskedTailingBits 后缀不脱敏位数，0 表示脱敏到末尾
     * @return 处理后的字符串
     */
    public static String masked(String s, int unmaskedLeadingBits, int unmaskedTailingBits) {
        if (s == null || s.length() <= 0) return "";
        if (unmaskedLeadingBits + unmaskedTailingBits >= s.length()) return s;
        if (unmaskedLeadingBits == 0 && unmaskedTailingBits == 0) return getNBitsAsterisk(s.length());

        return s.substring(0, unmaskedLeadingBits)
                + getNBitsAsterisk(s.length() - (unmaskedLeadingBits + unmaskedTailingBits))
                + s.substring(s.length() - unmaskedTailingBits);
    }

    // 根据支付宝的要求对姓名、身份证、手机号脱敏
    public static String maskedName(String s) {
        if (s != null && s.length() == 1) return "*";
        return masked(s, 0, 2);
    }

    public static String maskedIdCardNo(String s) {
        return masked(s, 1, 1);
    }


    public static HospitalCustomInfo getHospitalCustomInfo(int hospitalId) {
        HospitalCustomInfo def = genHospitalCustomInfo(0, "", "", "");
        return getHospitalCustomInfoList().stream().filter(i -> hospitalId == i.getHospitalId()).findFirst().orElse(def);
    }

    /**
     * 返回医院的别名和所在地区名称、地址等
     * 这些名称一般不会变动，所以直接 hard code。如果后续经常修改，可以维护进 hospital 表
     */
    public static List<HospitalCustomInfo> getHospitalCustomInfoList() {
        HospitalCustomInfo i1 = genHospitalCustomInfo(CheckInConstants.NFYYBYFY_SH_SUB_HOSPITAL_ID, "广州市天河区广州大道中1305号", "沙河院区", "广州天河区");
        HospitalCustomInfo i2 = genHospitalCustomInfo(CheckInConstants.NFYYBYFY_HS_SUB_HOSPITAL_ID, "广州市白云区黄石街元下底路23号", "黄石院区", "广州白云区");
        HospitalCustomInfo i3 = genHospitalCustomInfo(Constant.TAIHE_HOSPITAL_ID, "广州市白云区太和中路53号", "太和分院", "广州白云区");
        return Arrays.asList(i1, i2, i3);
    }

    public static HospitalCustomInfo genHospitalCustomInfo(int hospitalId, String addr, String alias, String area) {
        HospitalCustomInfo i = new HospitalCustomInfo();
        i.setHospitalId(hospitalId);
        i.setAddr(addr);
        i.setAlias(alias);
        i.setAreaName(area);
        return i;
    }

    /**
     * 根据医院 id 获取对应的互联网科室 id，目前只支持太和分院
     *
     * @param hospitalId 医院 id
     * @return 对应的互联网科室代号
     */
    public static String getNetDeptCodeByHospitalId(int hospitalId) {
        switch (hospitalId) {
            case Constant.TAIHE_HOSPITAL_ID:
                return Constant.TAIHE_NET_DEPT_CODE;
            case Constant.NFYYBYFY_HOSPITAL_ID:
                return Constant.NFYYBYFY_NET_DEPT_CODE;
            default:
                return "";
        }
    }

    /**
     * convert cent to yuan
     *
     * @param cent cent
     * @return value of yuan
     */
    public static double cent2Yuan(int cent) {
        BigDecimal v1 = new BigDecimal(String.valueOf(cent));
        BigDecimal v2 = new BigDecimal("100");
        BigDecimal result = v1.divide(v2, 2, RoundingMode.HALF_UP);
        return result.doubleValue();
    }

    /**
     * convert yuan to cent
     *
     * @param yuan yuan
     * @return value of cent
     */
    public static double yuan2Cent(double yuan) {
        BigDecimal v1 = new BigDecimal(String.valueOf(yuan));
        BigDecimal v2 = new BigDecimal("100");
        BigDecimal result = v1.multiply(v2);
        return result.intValue();
    }


}
