package com.ywt.outpatient.service.rpc;

import com.fasterxml.jackson.databind.JsonNode;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.system.GetConfigByIdRequest;
import com.ywt.gapi.system.GetConfigByIdResponse;
import com.ywt.gapi.system.GetConfigByTypeRequest;
import com.ywt.gapi.system.GetConfigByTypeResponse;
import com.ywt.outpatient.core.Constant;
import com.ywt.outpatient.core.Constants;
import com.ywt.outpatient.domain.entity.center.Config;
import com.ywt.outpatient.domain.entity.center.ConfigRepository;
import com.ywt.outpatient.domain.models.Covid19QuestionnaireConfig;
import com.ywt.outpatient.domain.models.OpenHisPushPayCodeConfigVo;
import com.ywt.outpatient.domain.models.config.*;
import com.ywt.outpatient.domain.models.enums.ConfigTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ConfigServiceProvider {
    private static final Logger logger = LoggerFactory.getLogger(ConfigServiceProvider.class);
    /**
     * 询诊订单默认价格
     */
    private final BigDecimal TREATMENT_AMOUNT = new BigDecimal(500);

    /**
     * 微信支付默认回调地址
     */
    private final String WECHAT_PAY_CALLBACK_URL = "https://pay.ywtinfo.com/wxa/notify";

    /**
     * 咨询订单默认价格，单位：分
     */
    private final int CONSULT_FEE = 3000;

    /**
     * 远程会诊订单默认价格，单位：分
     */
    private final int TREATMENT_FEE = 15000;

    /**
     * 医生推广费用（单位：分）默认值
     */
    private final int MARKETING_FEE = 5000;

    /**
     * 提交上月重点医生名单截止日
     */
    private final int MARKETING_DATE = 15;

    /**
     * 医生上月的患者数
     */
    private final int MARKETING_COUNT = 1;

    /**
     * 公医标识配置--医院ID
     */
    final static String FMT_HOSPITAL_ID = "hospitalId";

    /**
     * 公医标识配置--类型list
     */
    final static String FMT_TYPE_LIST = "typeList";

    @Autowired
    private ConfigRepository configRepository;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public BigDecimal getTreatmentPrice() {
        PriceConfig priceConfig = getPriceConfig();

        return priceConfig == null || priceConfig.getTreatmentPrice() == null ?
                TREATMENT_AMOUNT :
                priceConfig.getTreatmentPrice();
    }

    public int getConsultFee() {
        PriceConfig priceConfig = getPriceConfig();

        return priceConfig == null || priceConfig.getConsultFee() == null ?
                CONSULT_FEE :
                priceConfig.getConsultFee();
    }

    public int getTreatmentFee() {
        PriceConfig priceConfig = getPriceConfig();
        return priceConfig == null || priceConfig.getTreatmentFee() == null ?
                TREATMENT_FEE :
                priceConfig.getTreatmentFee();
    }

    public int getMarketingFee() {
        PriceConfig priceConfig = getPriceConfig();
        return priceConfig == null || priceConfig.getMarketingFee() == null ?
                MARKETING_FEE :
                priceConfig.getMarketingFee();
    }

    /**
     * 提交上月重点医生名单截止日
     *
     * @return
     */
    public int getMarketingDate() {
        PriceConfig priceConfig = getPriceConfig();
        return priceConfig == null || priceConfig.getMarketingDate() == null ?
                MARKETING_DATE :
                priceConfig.getMarketingDate();
    }

    public int getMarketingCount() {
        PriceConfig priceConfig = getPriceConfig();
        return priceConfig == null || priceConfig.getMarketingCount() == null ?
                MARKETING_COUNT :
                priceConfig.getMarketingCount();
    }

    /**
     * 患者是否可以向医药代表添加的医生问诊
     *
     * @return
     */
    public boolean getRepsEnable() {
        PriceConfig priceConfig = getPriceConfig();
        return priceConfig != null && priceConfig.getReps() != null && priceConfig.getReps() == 1;
    }

    public PriceConfig getPriceConfig() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.Price.getValue());

        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }

        return JsonSerializer.from(config.getContent(), PriceConfig.class);
    }

    public String getWeChatPayCallbackUrl() {
        UrlConfig config = getUrlConfig();
        return config == null || StringHelper.isNullOrEmpty(config.getWeChatPayCallbackUrl()) ?
                WECHAT_PAY_CALLBACK_URL :
                config.getWeChatPayCallbackUrl();
    }

    public UrlConfig getUrlConfig() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.Url.getValue());

        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }

        return JsonSerializer.from(config.getContent(), UrlConfig.class);
    }

    /**
     * 获取微信配置信息
     *
     * @return
     */
    public WeChatConfig getWeChatConfig() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.WeChat.getValue());

        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }

        return JsonSerializer.from(config.getContent(), WeChatConfig.class);
    }

    public String getVoiceSmsPhone() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.VoiceSms.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return "";
        }
        String content = config.getContent();
        try {
            VoiceSmsConfig cfg = JsonSerializer.from(content, VoiceSmsConfig.class);
            return cfg == null ? "" : Checker.getStringValue(cfg.getPhone());
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getVoiceSmsPhone(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return "";
    }

    public String getVoiceSmsTplId() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.VoiceSms.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return "";
        }
        String content = config.getContent();
        try {
            VoiceSmsConfig cfg = JsonSerializer.from(content, VoiceSmsConfig.class);
            return cfg == null ? "" : Checker.getStringValue(cfg.getTemplateId());
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getVoiceSmsPhone(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return "";
    }

    public Config getFmtConfig() {
        return configRepository.findOneByType(ConfigTypeEnum.FMT.getValue());
    }

    public List<String> getFmtFlagList(Config config, int hospitalId) {
        List<String> list = new LinkedList<>();
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return list;
        }
        String content = config.getContent();
        try {
            if (hospitalId == 0) {
                hospitalId = Constants.TAIHE_HOSPITAL_ID;
            }
            /**
             * content 举例：
             [{"hospitalId":12,"typeList":["白云区公医","公医","天河区公医"]},{"hospitalId":41,"typeList":["白云区公医41","公医41","天河区公医41"]}]
             *
             */
            JsonNode node = JsonSerializer.readToNode(content);
            if (node != null && node.isArray()) {
                for (JsonNode jsonNode : node) {
                    String obj = jsonNode.toString();
                    Map<String, Object> map = JsonSerializer.from(obj, Map.class);
                    if (map == null) {
                        return new LinkedList<>();
                    }
                    int hospitalIdValue = (int) map.getOrDefault(FMT_HOSPITAL_ID, 0);
                    if (hospitalIdValue == hospitalId) {
                        List<String> typeList = (List<String>) map.getOrDefault(FMT_TYPE_LIST, null);
                        if (typeList == null) {
                            return new LinkedList<>();
                        }
                        typeList.stream().forEach(p -> {
                            list.add(p);
                        });
                    }
                }
            }
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getVoiceSmsPhone(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return list;
    }

    /**
     * 获取云胶片订单价格配置
     *
     * @return 价格，单位: 分
     */
    public int getCloudFilmPrice() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.CLOUD_FILM_CFG.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return -1;
        }
        String content = config.getContent();
        try {
            CloudFilmConfig cfg = JsonSerializer.from(content, CloudFilmConfig.class);
            return cfg == null ? -1 : Checker.getIntegerValue(cfg.getCheckResultFee());
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getCloudFilmPrice(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return -1;
    }

    public String getCloudFilmPayCode() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.CLOUD_FILM_CFG.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return "";
        }
        String content = config.getContent();
        try {
            CloudFilmConfig cfg = JsonSerializer.from(content, CloudFilmConfig.class);
            return cfg == null ? "" : Checker.getStringValue(cfg.getPayCode());
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getCloudFilmPayCode(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return "";
    }

    public String getCloudFilmPayBody() {
        Config config = configRepository.findOneByType(ConfigTypeEnum.CLOUD_FILM_CFG.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return "";
        }
        String content = config.getContent();
        try {
            CloudFilmConfig cfg = JsonSerializer.from(content, CloudFilmConfig.class);
            return cfg == null ? "" : Checker.getStringValue(cfg.getPayBody());
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getCloudFilmPayBody(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return "";
    }

    public CloudFilmConfig getCloudFilmConfig(int hospitalId) {
        Config config = configRepository.findOneByType(ConfigTypeEnum.CLOUD_FILM_CFG.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }
        String content = config.getContent();
        try {
            JsonNode node = JsonSerializer.readToNode(content);
            if (node != null && node.isArray()) {
                for (JsonNode jsonNode : node) {
                    CloudFilmConfig c = JsonSerializer.from(jsonNode.toString(), CloudFilmConfig.class);
                    if (c != null && Checker.getIntegerValue(c.getHospitalId()) == hospitalId) {
                        return c;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getCloudFilmPrice(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return null;
    }

    public OutpatientConfig getOutpatientConfig(int hospitalId) {
        Config config = configRepository.findOneByType(ConfigTypeEnum.OUTPATIENT.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }
        String content = config.getContent();
        try {
            JsonNode node = JsonSerializer.readToNode(content);
            if (node != null && node.isArray()) {
                for (JsonNode jsonNode : node) {
                    OutpatientConfig c = JsonSerializer.from(jsonNode.toString(), OutpatientConfig.class);
                    if (c != null && Checker.getIntegerValue(c.getHospitalId()) == hospitalId) {
                        return c;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getOutpatientConfig(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return null;
    }


    private IcbcPayConfig getIcbcPayConfig(Config config) {
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }
        return JsonSerializer.from(config.getContent(), IcbcPayConfig.class);
    }

    private int getValueFromRedisByKey(String key) {
        String value = redisTemplate.opsForValue().get(key)+"";
        if (value != null) {
            return Integer.parseInt(value);
        }
        return 0;
    }
    private Config getCommonConfigByConfigType(int configType){
        String key = String.format("ywt_center.config_type_%d", configType);
        String value = redisTemplate.opsForValue().get(key)+"";
        Config config = null;

        if (value != null) {
            config = JsonSerializer.from(value, Config.class);
        } else {
            config = configRepository.findOneByType(configType);
            // 每天更新一次
            redisTemplate.opsForValue().set(key, JsonSerializer.toJson(config), Constant.YWT_CONFIG_EXPIRE_TIME, TimeUnit.SECONDS);
        }
        return config;
    }
    public GetConfigByTypeResponse getConfigByTypeResponse(GetConfigByTypeRequest request) {
        int configType = request.getConfigType();
        Config config = getCommonConfigByConfigType(configType);
        if (config == null) {
            return GetConfigByTypeResponse.newBuilder()
                    .setCode(ResultCode.PARAMETER_ERROR_VALUE)
                    .setMessage("该配置不存在")
                    .setConfigContent("")
                    .setCustomContent("")
                    .build();
        }
        // 得到配置的内容
        String configContent = Checker.getStringValue(config.getContent());
        logger.error("----getConfigByTypeResponse-----:{}", configContent);
        // 处理自定义配置
        String customContent = "";
        // isWeChatPay表示微信支付，0-否，1-是，默认采用微信
        int isWeChatPay = 1;
        if (configType == ConfigTypeEnum.ICBC_PAY_CONFIG.getValue()) {
            // 先处理工行的
            IcbcPayConfig icbcPayConfig = getIcbcPayConfig(config);
            logger.error("----getConfigByTypeResponse>>ICBC_PAY_CONFIG>>IcbcPayConfig-----:{}", JsonSerializer.toJson(icbcPayConfig));
            if (icbcPayConfig != null) {
                int wetchatPayInitCount = icbcPayConfig.getWechatPayInitCount();
                int icbcPayInitCount = icbcPayConfig.getIcbcPayInitCount();
                int addValue = wetchatPayInitCount + icbcPayInitCount;
                if (addValue == 0 || icbcPayInitCount == 0) {
                    // 默认采用微信支付
                    isWeChatPay = 1;
                } else if (wetchatPayInitCount == 0) {
                    // 如果微信支付为0，则采用工行支付
                    isWeChatPay = 0;
                } else {
                    // 两种支付方式都有的情况，则采用轮询的方法，先执行微信的数量，再执行icbc的数量，再执行微信的数量......如此循环
                    String wechatPayCountKey = String.format("ywt_center.config_wechat_pay_count_%d", configType);
                    String icbcPayCountKey = String.format("ywt_center.config_icbc_pay_count_%d", configType);

                    // 需要先初始化，如果已存在，则不会设置成功，如果不存在，则赋予初始值
                    redisTemplate.opsForValue().setIfAbsent(wechatPayCountKey, wetchatPayInitCount, Constant.YWT_CONFIG_EXPIRE_TIME, TimeUnit.SECONDS);

                    redisTemplate.opsForValue().setIfAbsent(icbcPayCountKey, icbcPayInitCount + "", Constant.YWT_CONFIG_EXPIRE_TIME, TimeUnit.SECONDS);

                    // 如果可以从weChat中获取到值 减1 之后 大于等于 0，那就选微信
                    if (redisTemplate.opsForValue().decrement(wechatPayCountKey) >= 0) {
                        isWeChatPay = 1;
                    } else if (redisTemplate.opsForValue().decrement(icbcPayCountKey) >= 0) {
                        // 如果微信获取不到，而icbc的值 减1 之后 大于等于 0，那就选icbc
                        isWeChatPay = 0;
                    } else {
                        isWeChatPay = 1;
                        // 此时表示两个都为0，进行重新设置，同时将微信的初始值-1
                        redisTemplate.opsForValue().set(wechatPayCountKey, (wetchatPayInitCount - 1) + "", Constant.YWT_CONFIG_EXPIRE_TIME, TimeUnit.SECONDS);
                        redisTemplate.opsForValue().set(icbcPayCountKey, icbcPayInitCount + "", Constant.YWT_CONFIG_EXPIRE_TIME, TimeUnit.SECONDS);
                    }
                }
            }

        } else if (configType == ConfigTypeEnum.OPEN_HIS_ICBC_PAY_CONFIG.getValue()) {
            // 先处理工行的
            OpenHisPushPayCodeConfigVo icbcPayConfig = parseOpenHisPushConfig(config.getContent());
            logger.error("----getConfigByTypeResponse>>OPEN_HIS_ICBC_PAY_CONFIG>>IcbcPayConfig-----:{}", JsonSerializer.toJson(icbcPayConfig));
            if (icbcPayConfig != null) {
                if (icbcPayConfig.getPrescriptionIcbcIsOpen()) {
                    // 如果微信支付为0，则采用工行支付
                    isWeChatPay = 0;
                }
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("isWeChatPay", isWeChatPay);
        customContent = JsonSerializer.toJson(map);
        return GetConfigByTypeResponse.newBuilder()
                .setCode(ResultCode.SUCCEED_VALUE)
                .setMessage("处理成功")
                .setConfigContent(configContent)
                .setCustomContent(customContent)
                .build();
    }

    /**
     * 根据 hospitalId 获取对应医院的 covid19_questionnaire 配置
     */
    public Covid19QuestionnaireConfig getCovid19QuestionnaireConfig(int hospitalId) {
        Config config = configRepository.findOneByType(ConfigTypeEnum.COVID19_QUESTIONNAIRE.getValue());
        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
            return null;
        }
        String content = config.getContent();
        try {
            JsonNode node = JsonSerializer.readToNode(content);
            if (node != null && node.isArray()) {
                for (JsonNode jsonNode : node) {
                    Covid19QuestionnaireConfig c = JsonSerializer.from(jsonNode.toString(), Covid19QuestionnaireConfig.class);
                    if (c != null && Checker.getIntegerValue(c.getHospitalId()) == hospitalId) {
                        return c;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("ConfigServiceProvider#getCovid19QuestionnaireConfig(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
        }
        return null;
    }

    public GetConfigByIdResponse getConfigById(GetConfigByIdRequest request) {
        int configId = request.getConfigId();
        GetConfigByIdResponse.Builder response = GetConfigByIdResponse.newBuilder()
                .setCode(ResultCode.SUCCEED_VALUE).setInfo("处理成功");
        Config config = configRepository.findById(configId).orElse(null);
        if (Checker.isNone(config)) {
            return response.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo("参数不能为空").build();
        }
        return response.setConfigContent(JsonSerializer.toJson(config)).setCustomContent(config.getContent()).build();
    }

    private OpenHisPushPayCodeConfigVo parseOpenHisPushConfig(String configContent) {
        try {
            return JsonSerializer.from(configContent, OpenHisPushPayCodeConfigVo.class);
        } catch (Exception e) {
            logger.error("ConfigService#parseOpenHisPushConfig():\n {}", e.getMessage(), e);
        }
        return null;
    }

    public String getOpenHisPushConfigPayCode() {
        int configType = ConfigTypeEnum.OPEN_HIS_ICBC_PAY_CONFIG.getValue();
        Config config = getCommonConfigByConfigType(configType);
        if (!Checker.isNone(config)) {
            String configContent = config.getContent();
            logger.error("--configContent--:" + configContent);
            if (!Checker.isNone(configContent)) {
                OpenHisPushPayCodeConfigVo vo = parseOpenHisPushConfig(configContent);
                if (!Checker.isNone(vo)) {
                    logger.error("--vo--:" + JsonSerializer.toJson(vo));
                    return vo.getPayCodeWithOutProportion();
                }
            }
        }
        return "1007";
    }

}
