package com.ywt.outpatient.service.rpc.common;

import com.google.gson.JsonObject;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.base.sms.SendSmsRequest;
import com.ywt.gapi.base.sms.SendSmsResponse;
import com.ywt.gapi.base.sms.SmsService;
import com.ywt.gapi.message.SmsMessageService;
import com.ywt.gapi.message.SmsTrackingData;
import com.ywt.outpatient.domain.entity.center.Doctor;
import com.ywt.outpatient.domain.entity.center.DoctorRepository;
import com.ywt.outpatient.domain.entity.center.Sms;
import com.ywt.outpatient.domain.entity.center.SmsRepository;
import com.ywt.outpatient.core.Constants;
import com.ywt.outpatient.domain.models.enums.SmsCodeTypeEnum;
import com.ywt.outpatient.domain.models.enums.SmsGroupEnum;
import com.ywt.outpatient.domain.models.enums.SmsSendStatusEnum;
import com.ywt.outpatient.service.rpc.DoctorService;
import com.ywt.outpatient.service.rpc.IdGenerator;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class SmsProvider {
    private static Logger logger = LoggerFactory.getLogger(SmsProvider.class);

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private SmsRepository smsRepository;

    @DubboReference
    SmsService smsServiceBlockingStub;

    @DubboReference
    SmsMessageService smsMessageServiceBlockingStub;// 新的统一短信服务

    @Autowired
    DoctorRepository doctorRepository;

    @Autowired
    DoctorService doctorService;

    //短信抬头
    private static final String SMS_SIGN_TH_NET_HOS = "互联网医院";
    private static final String SMS_SIGN_NF_HEALTH = "南方大健康";
    private static final String SMS_SIGN_YWT = "南方医务通";

    public ServiceResult sendSmsCode(String mobile, String code, int type, String smsSign, SmsTrackingData data) {
        ServiceResult result = new ServiceResult();
        SmsCodeTypeEnum typeEnum = SmsCodeTypeEnum.valueOf(type);

        if (typeEnum == null) {
            return result.failed("短信验证码类型不正确");
        }
        String serviceName = data.getServiceName();
        if (StringHelper.isNullOrEmpty(serviceName)) {
            serviceName = "rpc";
        }
        String methodName = data.getMethodName();
        if (StringHelper.isNullOrEmpty(methodName)) {
            methodName = "SmsProvider#sendSmsCode";
        }
        Map<String, Object> map = new HashMap<>();
        map.put("typeEnum", typeEnum);
        String extData = data.getExtData();
        if (!StringHelper.isNullOrEmpty(extData)) {
            map.put("extData", extData);
        }

        switch (typeEnum) {
            case Login:
            case Create_Patient:
            case WeChat_Mobile:
            case Medical_Card_Bind:
            case Forget_Password:
            case UPDATE_MOBILE:
            case MgAdmin_Bind_User:
                JsonObject object = new JsonObject();
                object.addProperty("captcha", code);
                return sendSmsNew(mobile, "SMS_4001", object.toString(), smsSign, data.getTerminal(), serviceName,
                        data.getIp(), methodName, data.getAuthData(), JsonSerializer.toJson(map));
            default:
                return result.failed("短信验证码类型不正确");
        }
    }

    /**
     * 根据医生所在医院判断短信内容显示的终端名称，规则如下：
     * 1. SMS_1001~SMS_1004 terminalName 以收到消息的医生所在的医院判定。
     * 南方医科大学南方医院白云分院的医生，终端显示"南方医院白云医疗集团互联网医院”；不是南方医科大学南方医院白云分院的医生，终端显示"南方医院太和互联网医院医生版”
     * 2. SMS_2001~SMS_2005 terminalName 根据发起业务的医生所在的医院判定
     * 南方医科大学南方医院白云分院的医生，终端显示"南方医科大学南方医院白云分院”；不是南方医科大学南方医院白云分院的医生，终端显示"南方医院太和互联网医院”
     */
    public String getTerminalNameByDoctorId(int doctorId, boolean isDoctorTerminal) {
        Doctor doctor = doctorRepository.findById(doctorId).orElse(null);
        int doctorHospitalId = doctorService.getHospitalId(doctor.getHospitalIds());
        if (isDoctorTerminal) {
            switch (doctorHospitalId) {
                case Constants.NFYYBYFY_HOSPITAL_ID:
                    return "南方医院白云医疗集团互联网医院微信公众号";
                default:
                    return "南方医院太和互联网医院医生版微信公众号";
            }
        } else {
            switch (doctorHospitalId) {
                case Constants.NFYYBYFY_HOSPITAL_ID:
                    return "南方医科大学南方医院白云分院微信小程序";
                default:
                    return "南方医院太和互联网医院微信公众号";
            }
        }
    }

    public ServiceResult notifyAfterCreateTreatmentOrder(String fromDoctorName, String toDoctorName, String toDoctorMobile,
                                                         int toDoctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", toDoctorName);
        object.addProperty("sponsor", fromDoctorName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(toDoctorId, true));
        return sendSmsNew(toDoctorMobile, "SMS_1001", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    public ServiceResult notifyAfterCreateReport(String fromDoctorName, String toDoctorName, String fromDoctorMobile,
                                                 int toDoctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", toDoctorName);
        object.addProperty("sponsor", fromDoctorName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(toDoctorId, true));
        return sendSmsNew(fromDoctorMobile, "SMS_1002", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    public ServiceResult notifyAfterCreateTransferOrder(String fromDoctorName, String toDoctorName, String toDoctorMobile,
                                                        int toDoctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", toDoctorName);
        object.addProperty("sponsor", fromDoctorName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(toDoctorId, true));
        return sendSmsNew(toDoctorMobile, "SMS_1003", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    public ServiceResult notifyAfterCreateConsultOrder(String doctorName, String patientName, String doctorMobile,
                                                       int toDoctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", doctorName);
        object.addProperty("sponsor", patientName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(toDoctorId, true));
        return sendSmsNew(doctorMobile, "SMS_1004", object.toString(), SMS_SIGN_TH_NET_HOS);
    }


    /**
     * 基层医生发送订单信息给患者（远程会诊）
     * <p>
     * 模版CODE:
     * SMS_122289936
     * 模版内容:
     * 亲爱的${name},您的远程会诊申请已经通过，请及时打开“南方医务通”微信公众号，进入“我的”-“服务记录”查看会诊信息并支付，以免错过会诊时间
     *
     * @param patientName
     * @param patientMobile
     * @return
     */
    public ServiceResult notifyPatientTreatmentOrder(String patientName, String patientMobile, int doctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", patientName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(doctorId, false));
        return sendSmsNew(patientMobile, "SMS_2001", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    /**
     * 基层医生发送远程会诊专家报告给患者（远程会诊）
     * <p>
     * 模版CODE:
     * SMS_123670001
     * 模版内容:
     * 亲爱的${name},您收到一份远程会诊专家报告，请及时打开“南方医务通”微信公众号，进入“我的”-“服务记录”查看。
     *
     * @param patientName
     * @param patientMobile
     * @return
     */
    public ServiceResult notifyPatientTreatmentReport(String patientName, String patientMobile, int doctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", patientName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(doctorId, false));
        return sendSmsNew(patientMobile, "SMS_2002", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    /**
     * 基层医生通知床位信息给患者（双向转诊）
     * <p>
     * 模版CODE:
     * SMS_123665060
     * 模版内容:
     * 亲爱的${name},您的转诊申请已经通过，请及时打开“南方医务通”微信公众号，进入“我的”-“服务记录”查看转诊信息并确认，以免错过床位。
     *
     * @param patientName
     * @param patientMobile
     * @return
     */
    public ServiceResult notifyPatientTransferOrder(String patientName, String patientMobile, int doctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", patientName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(doctorId, false));
        return sendSmsNew(patientMobile, "SMS_2003", object.toString(), SMS_SIGN_TH_NET_HOS);
    }


    /**
     * 医生发起随访
     * <p>
     * 模版CODE:
     * SMS_123665216
     * 模版内容:
     * 亲爱的${name}，${doctorName}向您发起了随访，请及时打开“南方医务通”微信公众号，进入“我的”-“服务记录”查看并回复医生，24h后随访结束。
     *
     * @param hospitalName
     * @param doctorName
     * @param patientName
     * @param patientMobile
     * @return
     */
    public ServiceResult notifyPatientFollowUpOrder(String hospitalName, String doctorName, String patientName, String patientMobile,
                                                    int doctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", patientName);
        object.addProperty("hospital", hospitalName);
        object.addProperty("doctor", doctorName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(doctorId, false));
        return sendSmsNew(patientMobile, "SMS_2004", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    /**
     * 收到处方
     * <p>
     * 模版CODE:
     * SMS_126358847
     * 模版内容:
     * 亲爱的${name}，${hopital}的${doctorName}医生给您开了处方单，
     * 请及时打开“南方医务通”微信公众号，进入“医疗服务”-“我的处方”查看并支付。
     *
     * @param hospitalName
     * @param doctorName
     * @param patientName
     * @param patientMobile
     * @return
     */
    public ServiceResult notifyAfterCreatePrescription(String hospitalName, String doctorName, String patientName,
                                                       String patientMobile, int doctorId) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", patientName);
        object.addProperty("hospital", hospitalName);
        object.addProperty("doctor", doctorName);
        object.addProperty("terminalName", getTerminalNameByDoctorId(doctorId, false));
        return sendSmsNew(patientMobile, "SMS_2005", object.toString(), SMS_SIGN_TH_NET_HOS);
    }

    /**
     * 南方大健康添加代表
     *
     * @param phoneNumber 接收短信手机号
     * @param defaultPsw  默认密码
     * @return result
     */
    public ServiceResult notifyAddRepresentative(String phoneNumber, String defaultPsw) {
        JsonObject object = new JsonObject();
        object.addProperty("phone", phoneNumber);
        object.addProperty("psw", defaultPsw);
        return sendSmsNew(phoneNumber, "SMS_3001", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    /**
     * 添加药商
     *
     * @param phoneNumber 接收短信手机号
     * @param defaultPsw  默认密码
     * @return result
     */
    public ServiceResult notifyAddMerchant(String phoneNumber, String defaultPsw) {
        JsonObject object = new JsonObject();
        object.addProperty("phone", phoneNumber);
        object.addProperty("psw", defaultPsw);
        return sendSmsNew(phoneNumber, "SMS_3002", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    /**
     * 南方大健康重置密码
     *
     * @param phoneNumber 手机号
     * @param psw         密码
     * @return result
     */
    public ServiceResult notifyResetPsw(String phoneNumber, String psw) {
        JsonObject object = new JsonObject();
        object.addProperty("psw", psw);
        return sendSmsNew(phoneNumber, "SMS_3003", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    /**
     * 管理后台添加的一级经销商或者修改手机号发送短信通知
     *
     * @param phone 手机号
     * @return
     */
    @SuppressWarnings("javadoc")
    public ServiceResult notifyAddedSubDealersFromMG(String phone) {
        JsonObject object = new JsonObject();
        object.addProperty("phone", phone);
        return sendSmsNew(phone, "SMS_3004", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    /**
     * 南方大健康添加的一级经销商或者修改手机号发送短信通知
     *
     * @param phone
     * @param receiverName
     * @param superiorName
     * @param superiorPhone
     * @return
     */
    public ServiceResult notifyAddedSubDealersFromNFHealth(String phone, String receiverName, String superiorName, String superiorPhone) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", receiverName);
        object.addProperty("superiorName", superiorName);
        object.addProperty("superiorPhone", superiorPhone);
        return sendSmsNew(phone, "SMS_3005", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    /**
     * 南方大健康 修改经销商手机号和添加经销商下发通知
     *
     * @param phone        接收方手机号
     * @param receiverName 接收者姓名
     * @param superiorName 上级姓名
     * @return {@link ServiceResult}
     */
    public ServiceResult notifyAddedSubDealersFromNFHealthNew(String phone, String receiverName, String superiorName) {
        JsonObject object = new JsonObject();
        object.addProperty("receiver", receiverName);
        object.addProperty("superior", superiorName);
        return sendSmsNew(phone, "SMS_3006", object.toString(), SMS_SIGN_NF_HEALTH);
    }

    private ServiceResult sendSmsNew(String phoneNumbers, String templateCode, String params) {
        return sendSmsNew(phoneNumbers, templateCode, params, "");
    }

    /**
     * 兼容方法
     */
    private ServiceResult sendSmsNew(String phoneNumbers, String templateCode, String params, String smsSign) {
        return sendSmsNew(phoneNumbers, templateCode, params, smsSign, 0, "", "", "", "", "");
    }

    /**
     * 统一短信消息服务
     *
     * @param phoneNumbers 短信接收手机号，多个手机号为用半角 , 分开，如13899999999,13688888888
     * @param templateCode 短信模板编号，定义在sms_template表中
     * @param params       短信模板参数
     * @param smsSign      短信开头的签名，不填默认：南方医务通
     * @return
     */
    private ServiceResult sendSmsNew(String phoneNumbers, String templateCode, String params, String smsSign,
                                     int terminal,
                                     String serviceName,
                                     String ip,
                                     String methodName,
                                     String authData,
                                     String extData) {
        ServiceResult result = new ServiceResult();
        try {
            SmsTrackingData data = SmsTrackingData.newBuilder()
                    .setTerminal(terminal)
                    .setServiceName(serviceName)
                    .setIp(ip)
                    .setMethodName(methodName)
                    .setAuthData(authData)
                    .setExtData(extData)
                    .build();
            com.ywt.gapi.message.SendSmsRequest request = com.ywt.gapi.message.SendSmsRequest.newBuilder()
                    .setPhoneNumbers(phoneNumbers)
                    .setTemplateCode(templateCode)
                    .setTemplateParam(params)
                    .setSmsSign(StringHelper.isNullOrEmpty(smsSign) ? SMS_SIGN_YWT : smsSign)
                    .setSmsTrackingData(data)
                    .build();
            com.ywt.gapi.message.SendSmsResponse response = smsMessageServiceBlockingStub.sendSms(request);

            switch (response.getCode()) {
                case ResultCode.APP_EXCEPTION_VALUE:
                    return result.succeed("发送出错");
                case ResultCode.SUCCEED_VALUE:
                    return result.succeed("发送成功");
                default:
                    return result.failed("发送失败");
            }
        } catch (Exception e) {
            logger.error("sendSms(): {}", e.getMessage(), e);
            return result.failed(String.format("发送出错，错误信息：%s", e.getMessage()));
        }
    }

    ///////////////////////////////////////////////////////////////
    //
    //      marked as deprecated methods by Walker
    //      on 2018-06-04
    //
    ///////////////////////////////////////////////////////////////

    @Deprecated
    public ServiceResult notifyAfterCreateAttendingOrder(String fromDoctorName, String toDoctorName, String toDoctorMobile) {
        final String tplCode = "SMS_122293915";
        Map<String, Object> map = new HashMap<>();
        map.put("doctorNameNo1", toDoctorName + "医生");
        map.put("doctorNameNo2", fromDoctorName + "医生");
        map.put("biz", "外请会诊");

        return saveAndSendSms(toDoctorMobile, tplCode, JsonSerializer.toJson(map), SmsGroupEnum.NOTIFY.getValue());
    }

    /**
     * @param patientName
     * @param patientMobile
     * @return
     * @deprecated since 2018-05-31
     * 基层医生通知患者到诊（外请会诊）
     * <p>
     * 模版CODE:
     * SMS_123665012
     * 模版内容:
     * 亲爱的${name},您的外请会诊申请已经通过，请及时打开“南方医务通”微信公众号，进入“我的”-“服务记录”查看外诊信息并确认，以免错过会诊时间。
     */
    @Deprecated
    public ServiceResult notifyPatientAttendingOrder(String patientName, String patientMobile) {
        final String tplCode = "SMS_123665012";
        Map<String, Object> map = new HashMap<>();
        map.put("name", patientName);
        return saveAndSendSms(patientMobile, tplCode, JsonSerializer.toJson(map), SmsGroupEnum.NOTIFY.getValue());
    }

    /**
     * 保存并发送短信
     *
     * @param mobile
     * @param tplCode
     * @param tplParam
     * @param group
     * @return
     */
    @Deprecated
    private ServiceResult saveAndSendSms(String mobile, String tplCode, String tplParam, int group) {
        return saveAndSendSms(mobile, tplCode, tplParam, group, 0);
    }

    /**
     * 保存并发送短信
     *
     * @param mobile
     * @param tplCode
     * @param tplParam
     * @param group
     * @return
     */
    @Deprecated
    private ServiceResult saveAndSendSms(String mobile, String tplCode, String tplParam, int group, int type) {
        int id = idGenerator.generateSmsId();
        Sms sms = new Sms();
        sms.setId(id);
        sms.setMobile(mobile);
        sms.setContent("");
        sms.setDeleted(false);
        sms.setUserId(0);
        sms.setType(type);
        sms.setCreateTime(new Date());
        sms.setSendStatus(SmsSendStatusEnum.Sending.getValue());
        sms.setTemplateCode(tplCode);
        sms.setData(tplParam);
        sms.setGroup(group);

        smsRepository.save(sms);
        return sendSms(sms);
    }

    /**
     * 发送短信，调用阿里云短信服务接口
     *
     * @param sms
     * @return
     */
    @Deprecated
    private ServiceResult sendSms(Sms sms) {
        ServiceResult result = new ServiceResult();

        try {
            SendSmsRequest req = SendSmsRequest.newBuilder()
                    .setPhoneNumbers(sms.getMobile())
                    .setTplCode(sms.getTemplateCode())
                    .setTplParam(sms.getData())
                    .setOutId(String.valueOf(sms.getId()))
                    .build();
            SendSmsResponse res = smsServiceBlockingStub.sendSms(req);

            if (res.getCode() != ResultCode.APP_EXCEPTION_VALUE) {
                sms.setRequestId(res.getRequestId());
                sms.setBizId(res.getBizId());
                sms.setCode(res.getStatusCode());
                sms.setMessage(res.getMessage());

                smsRepository.save(sms);

                if (res.getCode() == ResultCode.SUCCEED_VALUE) {
                    return result.succeed("发送成功");
                }

                return result.failed("发送失败");
            }

            return result.succeed("发送出错");
        } catch (Exception e) {
            logger.error("sendSms(): {}", e.getMessage(), e);
            return result.failed(String.format("发送出错，错误信息：%s", e.getMessage()));
        }
    }
}
