package com.ywt.outpatient.service.web.taihe;


import com.ywt.biz.common.util.CacheUtil;
import com.ywt.biz.common.util.PhoneNumChecker;
import com.ywt.biz.common.util.RandomUtil;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.Result;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.message.MessageService;
import com.ywt.gapi.message.SendSmsCodeRequest;
import com.ywt.gapi.message.SendSmsCodeResponse;
import com.ywt.gapi.message.SmsTrackingData;
import com.ywt.gapi.system.*;
import com.ywt.outpatient.core.BaseResponse;
import com.ywt.outpatient.core.Constant;
import com.ywt.outpatient.core.structs.TrieTree;
import com.ywt.outpatient.domain.models.RedisCacheKey;
import com.ywt.outpatient.domain.models.enums.SmsCodeTypeEnum;
import com.ywt.outpatient.service.web.MessageSrv;
import com.ywt.outpatient.core.WebAppContext;
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.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Scope("singleton")
public class TaiheSystemService {
    private static Logger logger = LoggerFactory.getLogger(TaiheSystemService.class);

    private final String ICD_CODE_LIST = "TH_ICD_CODE_LIST";
    private final String HOSPITAL_LIST = "TH_HOSPITAL_LIST";
    private final String ICD_CODE_TRIE_TREE = "TH_ICD_CODE_TRIE_TREE";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @DubboReference
    private MessageService messageServiceBlockingStub;

    @DubboReference
    private SystemService systemServiceBlockingStub;

    @Autowired
    private MessageSrv messageSrv;

    /**
     * 根据名称关键词搜索诊断结果
     *
     * @param name 名称
     * @return
     */
    public List<IcdCode> getIcdCodeByName(String name) {
        List<IcdCode> list = getIcdCodeListFromCache();
        return list.stream().filter(p -> p.getName().contains(name)).collect(Collectors.toList());
    }

    /**
     * 根据名称拼音搜索诊断结果
     *
     * @param pinyin 名称拼音
     * @return
     */
    public List<IcdCode> getIcdCodeByPinYin(String pinyin) {
        if (StringHelper.isNullOrWhiteSpace(pinyin)) {
            return null;
        }

        TrieTree<IcdCode> trieTree = getIcdCodeTrieTree();
        return trieTree.searchByPrefix(pinyin.toUpperCase());
    }

    /**
     * @return
     */
    public TrieTree<IcdCode> getIcdCodeTrieTree() {
        try {
            return (TrieTree<IcdCode>) CacheUtil.getInstance().get(ICD_CODE_TRIE_TREE, new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    TrieTree<IcdCode> trieTree = new TrieTree<>();
                    List<IcdCode> lst = getIcdCodeListFromCache();
                    if (lst == null || lst.size() == 0) {
                        return trieTree;
                    }
                    for (IcdCode code : lst) {
                        trieTree.insert(code.getPyCode().toUpperCase(), code);
                    }
                    return trieTree;
                }
            });
        } catch (Exception e) {

        }

        return new TrieTree<>();
    }

    public List<IcdCode> getIcdCodeListFromCache() {
        try {
            return (List<IcdCode>) CacheUtil.getInstance().get(ICD_CODE_LIST, () -> getIcdCodeList());
        } catch (Exception e) {
            logger.error("TaiheSystemService#getIcdCodeListFromCache():\n {}", e.getMessage(), e);
        }
        return new LinkedList<>();
    }

    public List<IcdCode> getIcdCodeList() {
        try {
            GetIcdCodeListRequest req = GetIcdCodeListRequest.newBuilder().build();
            GetIcdCodeListResponse res = systemServiceBlockingStub.getIcdCodeList(req);
            Result result = res.getResult();

            if (result.getCode() == ResultCode.SUCCEED) {
                return res.getCodeList();
            }
        } catch (Exception e) {
            logger.error("getIcdCodeList(): {}", e.getMessage(), e);
        }

        return new LinkedList<>();
    }

    /**
     * 获取科室列表
     *
     * @param hospitalId 医院ID
     * @return
     */
    public List<Dept> getDeptList(int hospitalId) {
        DeptListRequest request = DeptListRequest.newBuilder().setHospitalId(hospitalId).build();
        DeptListResponse response = systemServiceBlockingStub.getDeptList(request);
        Result result = response.getResult();

        if (result.getCode() == ResultCode.SUCCEED) {
            return response.getDeptListList();
        }

        return null;
    }

    /**
     * 获取科室Map
     *
     * @param hospitalId 医院ID
     * @return
     */
    public Map<String, String> getDeptMap(int hospitalId) {
        Map<String, String> map;

        try {
            List<Dept> deptList = getDeptList(hospitalId);
            map = deptList.stream().collect(Collectors.toMap(Dept::getDeptCode, Dept::getDeptName, (key1, key2) -> key2));

            if (map == null) {
                map = new HashMap<>();
            }
        } catch (Exception e) {
            logger.error("getDeptMap():{}", e.getMessage());
            map = new HashMap<>();
        }

        return map;
    }

    /**
     * 根据名称关键词搜索诊断结果
     *
     * @param name 名称
     * @return
     */
    public List<Hospital> getHospitalListByName(String name) {
        List<Hospital> list = getHospitalListFromCache();
        return list.stream().filter(p -> p.getHospitalName().contains(name)).collect(Collectors.toList());
    }

    public List<Hospital> getHospitalListFromCache() {
        try {
            return (List<Hospital>) CacheUtil.getInstance().get(HOSPITAL_LIST, () -> getHospitalList(1, 1000));
        } catch (Exception e) {
            logger.error("TaiheSystemService#getHospitalListFromCache():\n {}", e.getMessage(), e);
        }
        return new LinkedList<>();
    }


    /**
     * 根据名称关键词搜索诊断结果
     *
     * create by daiyihua
     * @param name 名称
     * @return
     */
    public List<Dept> getDeptListByName(String name) {
        List<Dept> deptList = getDeptList(0);
        return deptList.stream().filter(p -> p.getDeptName().contains(name)).collect(Collectors.toList());
    }


    public List<Hospital> getHospitalList(int pageIndex, int pageSize) {
        HospitalListRequest request = HospitalListRequest.newBuilder()
                .setPageIndex(pageIndex)
                .setPageSize(pageSize)
                .build();
        HospitalListResponse response = systemServiceBlockingStub.getHospitalList(request);
        Result result = response.getResult();

        if (result.getCode() == ResultCode.SUCCEED) {
            return response.getHospitalListList();
        }

        return null;
    }

    /**
     * 获取医院科室列表（按上下级关系返回）
     *
     * @param hospitalId 医院Id
     * @return
     */
    public List<HospitalDept> getHospitalDeptList(int hospitalId) {
        HospitalDeptListRequest request = HospitalDeptListRequest.newBuilder()
                .setHospitalId(hospitalId)
                .build();
        HospitalDeptListResponse response = systemServiceBlockingStub.getHospitalDeptList(request);
        Result result = response.getResult();

        if (result.getCode() == ResultCode.SUCCEED) {
            return response.getHospitalDeptListList();
        }

        return null;
    }

    /**
     * 获取微信配置信息
     *
     * @return
     */
    public WeChatConfig getWeChatConfig() {
        GetWeChatConfigRequest req = GetWeChatConfigRequest.newBuilder().build();
        GetWeChatConfigResponse res = systemServiceBlockingStub.getWeChatConfig(req);
        Result result = res.getResult();

        if (result.getCode() == ResultCode.SUCCEED) {
            return res.getConfig();
        }

        return null;
    }

    public BaseResponse sendSmsCode(String mobile, int type) {
        BaseResponse response = verify(mobile, type);

        if (response.getCode() != BaseResponse.SUCCEED) {
            return response;
        }

        String code = RandomUtil.getRandomCode(6, 1);
        String key = String.format(RedisCacheKey.SMS_CODE_KEY_FORMAT, mobile, type);
        int expired = Constant.YWT_SMS_CODE_EXPIRE_TIME;// 15 * 60;  //验证码有效时间

        try {
            // 限制次数，每天最多5次
            String limitKey = String.format(RedisCacheKey.SMS_MOBILE_KEY_FORMAT, mobile, type);
            if (!messageSrv.checkSendStatus(limitKey)) {
                return response.failedWithParameterError("超出次数");
            }
            Map<String, Object> authDataMap = new HashMap<>();
            authDataMap.put("unionId", WebAppContext.current().getUnionId());
            authDataMap.put("openId", WebAppContext.current().getOpenId());
            authDataMap.put("userId", WebAppContext.current().getUserId());
            SmsTrackingData data = SmsTrackingData.newBuilder()
                    .setIp(WebAppContext.current().getIP())
                    .setServiceName("wapapi")
                    .setMethodName("TaiheSystemService#sendSmsCode")
                    .setTerminal(WebAppContext.current().getTerminal())
                    .setAuthData(JsonSerializer.toJson(authDataMap))
                    .build();
            SendSmsCodeRequest sendSmsCodeRequest = SendSmsCodeRequest.newBuilder()
                    .setType(type)
                    .setCode(code)
                    .setMobile(mobile)
                    .setSmsTrackingData(data)
                    .build();
            SendSmsCodeResponse sendSmsCodeResponse = messageServiceBlockingStub.sendSmsCode(sendSmsCodeRequest);
            Result result = sendSmsCodeResponse.getResult();

            if (result.getCode() == ResultCode.SUCCEED) {
                redisTemplate.opsForValue().set(key, code, expired, TimeUnit.SECONDS);
                return response.succeed(result.getInfo());
            }

            return response.failed(BaseResponse.OTHER_ERROR, result.getInfo());
        } catch (Exception e) {
            logger.error(String.format("sendSmsCode(\"%s\", %s)", mobile, type), e);
            return response.failed(BaseResponse.APP_EXCEPTION, e.getMessage());
        }
    }


    public BaseResponse checkSmsCode(String mobile, String code, int type) {
        BaseResponse response = verify(mobile, type);

        if (response.getCode() != BaseResponse.SUCCEED) {
            return response;
        }

        String key = String.format(RedisCacheKey.SMS_CODE_KEY_FORMAT, mobile, type);
        String val = redisTemplate.opsForValue().get(key)+"";

        if (val != null && val.equals(code)) {
            redisTemplate.delete(key);
            response.setCode(BaseResponse.SUCCEED);

            return response;
        }

        return response.failed(BaseResponse.PARAMETER_ERROR, "验证码不正确");
    }


    private BaseResponse verify(String mobile, int type) {
        BaseResponse response = new BaseResponse();

        if (!PhoneNumChecker.isPhoneNum(mobile)) {
            return response.failed(BaseResponse.PARAMETER_ERROR, "手机号码不正确");
        }

        SmsCodeTypeEnum typeEnum = SmsCodeTypeEnum.valueOf(type);

        if (typeEnum == null) {
            return response.failed(BaseResponse.PARAMETER_ERROR, "未定义业务类型");
        }

        return response.succeed();
    }
}