package com.ywt.outpatient.service.web;

import com.ywt.biz.common.util.CacheUtil;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.PhoneNumChecker;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.gapi.Result;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.base.sms.SendSMSFreeRequest;
import com.ywt.gapi.base.sms.SendSMSFreeResponse;
import com.ywt.gapi.base.sms.SmsService;
import com.ywt.gapi.message.MessageService;
import com.ywt.gapi.system.*;
import com.ywt.outpatient.api.union_reg.HospitalCustomInfo;
import com.ywt.outpatient.core.BaseResponse;
import com.ywt.outpatient.core.structs.TrieTree;
import com.ywt.outpatient.core.utils.BizUtil;
import com.ywt.outpatient.core.Constant;
import com.ywt.outpatient.domain.models.enums.SmsCodeTypeEnum;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

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

    // 疾病分类列表缓存键
    private final String ICD_CODE_LIST = "ICD_CODE_LIST";
    // 医院列表缓存键
    private final String HOSPITAL_LIST = "HOSPITAL_LIST";
    // 疾病分类字典树缓存键
    private final String ICD_CODE_TRIE_TREE = "ICD_CODE_TRIE_TREE";

    @DubboReference
    private SystemService systemServiceBlockingStub;

    @DubboReference
    private MessageService messageServiceBlockingStub;

    @DubboReference
    private SmsService smsServiceBlockingStub;

    /**
     * 根据名称关键词搜索诊断结果
     *
     * @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("SystemSrv#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<>();
    }

    /**
     * 医生团队（展示的）领衔医生所在的一级科室
     *
     * @return
     */
    public List<Dept> getTeamDeptList() {
        GetTeamDeptListRequest req = GetTeamDeptListRequest.newBuilder().build();
        GetTeamDeptListResponse res = systemServiceBlockingStub.getTeamDeptList(req);

        if (res.getCode() == ResultCode.SUCCEED_VALUE) {
            return res.getDeptList();
        }

        return new LinkedList<>();
    }

    /**
     * 医生团队（展示的）领衔医生所在的一级科室
     *
     * @return
     */
    public BaseResponse getTeamDeptListRes() {
        BaseResponse response = new BaseResponse();
        Map<String, Object> map;
        List<Map<String, Object>> lst = new LinkedList<>();

        try {
            GetTeamDeptListRequest req = GetTeamDeptListRequest.newBuilder().build();
            GetTeamDeptListResponse res = systemServiceBlockingStub.getTeamDeptList(req);

            if (res.getCode() == ResultCode.SUCCEED_VALUE) {
                for (Dept dept : res.getDeptList()) {
                    map = new HashMap<>();
                    map.put("deptId", dept.getDeptId());
                    map.put("deptName", dept.getDeptName());

                    lst.add(map);
                }

                Map<String, Object> data = new HashMap<>();
                data.put("list", lst);
                return response.succeed(data);
            }

            return response.failed(BaseResponse.APP_ERROR, res.getMsg());
        } catch (Exception e) {
            logger.error("getTeamDeptListRes(): {}", e.getMessage(), e);
            return response.error();
        }
    }

    /**
     * 获取地区列表（树状结构）
     *
     * @return
     */
    public BaseResponse getAreaTreeNodeList() {
        BaseResponse response = new BaseResponse();
        GetAreaTreeNodeListRequest req = GetAreaTreeNodeListRequest.newBuilder().build();
        GetAreaTreeNodeListResponse res = systemServiceBlockingStub.getAreaTreeNodeList(req);
        Result result = res.getResult();

        if (result.getCode() == ResultCode.SUCCEED) {
            List<Map<String, Object>> lst = getAreaMap(res.getAreaList());
            Map<String, Object> data = new HashMap<>();
            data.put("list", lst);

            return response.succeed(data);
        }

        return response.failed(BaseResponse.APP_ERROR, result.getInfo());
    }

    private List<Map<String, Object>> getAreaMap(List<TreeNode> nodeList) {
        List<Map<String, Object>> lst = new LinkedList<>();
        Map<String, Object> map = null;

        if (nodeList != null && nodeList.size() > 0) {
            for (TreeNode node : nodeList) {
                map = new HashMap<>();
                map.put("parentId", node.getParentId());
                map.put("id", node.getId());
                map.put("label", node.getLabel());
                map.put("children", getAreaMap(node.getChildrenList()));

                lst.add(map);
            }
        }

        return lst;
    }

    /**
     * 获取科室列表
     *
     * @param hospitalId    医院ID
     * @param subHospitalId 下级医院ID
     * @return
     */
    public BaseResponse getDeptList(int hospitalId, int subHospitalId, String name) {
        BaseResponse response = new BaseResponse();
        logger.error("getDeptList():hospitalId:{}, subHospitalId:{}", hospitalId, subHospitalId);
        try {
            List<HospitalDept> deptList = null;
            HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setSubHospitalId(subHospitalId)
                    .build();
            HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
            Result result = res.getResult();

            if (result.getCode() == ResultCode.SUCCEED) {
                deptList = res.getHospitalDeptListList();
            }

            if (deptList == null) {
                return response.failed(BaseResponse.PARAMETER_ERROR, "科室不存在");
            }

            List<Map<String, Object>> lst = new LinkedList<>();

            if (!Checker.isNone(name)) {
                for (HospitalDept d : deptList) {
                   if(d.getDeptName().contains(name)){
                       Map<String, Object> map = new HashMap<>();
                       map.put("deptId", d.getDeptId());
                       map.put("deptCode", d.getDeptCode());
                       map.put("deptName", d.getDeptName());

                       List<Map<String, Object>> secondList = new LinkedList<>();
                       for (Dept secDept : d.getDeptListList()) {
                           Map<String, Object> sec = new HashMap<>();
                           sec.put("deptId", secDept.getDeptId());
                           sec.put("deptCode", secDept.getDeptCode());
                           sec.put("deptName", secDept.getDeptName());

                           secondList.add(sec);
                       }

                       map.put("secondList", secondList);
                       lst.add(map);
                   } else {
                       List<Dept> filteredSecondDeptList = d.getDeptListList().stream().filter(cd -> Checker.getStringValue(cd.getDeptName()).contains(name)).collect(Collectors.toList());
                       if (filteredSecondDeptList.size() > 0) {
                           Map<String, Object> map = new HashMap<>();
                           map.put("deptId", d.getDeptId());
                           map.put("deptCode", d.getDeptCode());
                           map.put("deptName", d.getDeptName());

                           List<Map<String, Object>> secondList = new LinkedList<>();
                           for (Dept secDept : filteredSecondDeptList) {
                               Map<String, Object> sec = new HashMap<>();
                               sec.put("deptId", secDept.getDeptId());
                               sec.put("deptCode", secDept.getDeptCode());
                               sec.put("deptName", secDept.getDeptName());

                               secondList.add(sec);
                           }
                           map.put("secondList", secondList);
                           lst.add(map);
                       }
                   }
                }
            } else {
                for (HospitalDept d : deptList) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("deptId", d.getDeptId());
                    map.put("deptCode", d.getDeptCode());
                    map.put("deptName", d.getDeptName());

                    List<Map<String, Object>> secondList = new LinkedList<>();
                    for (Dept secDept : d.getDeptListList()) {
                        Map<String, Object> sec = new HashMap<>();
                        sec.put("deptId", secDept.getDeptId());
                        sec.put("deptCode", secDept.getDeptCode());
                        sec.put("deptName", secDept.getDeptName());

                        secondList.add(sec);
                    }

                    map.put("secondList", secondList);
                    lst.add(map);
                }
            }

            Map<String, Object> data = new HashMap<>();
            data.put("list", lst);

            return response.succeed("处理成功", data);
        } catch (Exception e) {
            logger.error("getDeptList(): {}", e.getMessage());
            return response.failed(BaseResponse.APP_EXCEPTION, Constant.ERROR_PROMPT);
        }
    }

    /**
     * 获取科室列表（不分级）
     *
     * @param hospitalId
     * @return
     */
    public List<Dept> getDeptListByHospitalId(int hospitalId) {
        DeptListRequest req = DeptListRequest.newBuilder()
                .setHospitalId(hospitalId)
                .build();
        DeptListResponse res = systemServiceBlockingStub.getDeptList(req);
        Result result = res.getResult();

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

        return null;
    }

    /**
     * 获取科室列表
     *
     * @param hospitalId 医院ID
     * @return
     */
    public List<Dept> getDeptList2(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 = getDeptList2(hospitalId);
            map = deptList.stream().collect(
                    Collectors.toMap(Dept::getDeptCode, Dept::getDeptName, (key1, key2) -> key2));
        } 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 String getHospitalNameById(int hospitalId) {
        List<Hospital> list = getHospitalListFromCache();
        Hospital hospital = list.stream().filter(h -> hospitalId == h.getHospitalId()).findFirst().orElse(null);
        return hospital == null ? "" : Checker.getStringValue(hospital.getHospitalName());
    }

    public com.ywt.gapi.system.Hospital getHospitalById(int hospitalId) {
        List<Hospital> list = getHospitalListFromCache();
       return list.stream().filter(h -> hospitalId == h.getHospitalId()).findFirst().orElse(null);
    }

    private List<Hospital> getHospitalListFromCache() {
        try {
            return (List<Hospital>) CacheUtil.getInstance().get(HOSPITAL_LIST, () -> getHospitalList(1, 1000));
        } catch (Exception e) {
            logger.error("getHospitalListFromCache：{}", e.getMessage());
        }
        return new LinkedList<>();
    }

    /**
     * 找医院
     *
     * @param keyWord 关键字，匹配医院名称
     * @param areaIds 地区id
     * @return 医院列表
     */
    public List<Hospital> findHospitals(String keyWord, String areaIds) {
        List<Hospital> list = getHospitalListFromCache();
        if (!StringHelper.isNullOrEmpty(keyWord)) {
            list = list.stream().filter(hospital -> hospital.getHospitalName().contains(keyWord)).collect(Collectors.toList());
        }
        if (!StringHelper.isNullOrEmpty(areaIds)) {
            String filterOpt = "," + areaIds + ",";
            list = list.stream().filter(hospital -> hospital.getAreaIds().contains(filterOpt)).collect(Collectors.toList());
        }
        return list;
    }


    /**
     * 根据名称关键词搜索诊断结果
     * <p>
     * create by daiyihua
     *
     * @param name 名称
     * @return
     */
    public List<Dept> getDeptListByName(String name) {
        List<Dept> deptList = getDeptList2(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;
    }

    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();
    }


    /**
     * 发送自由风格的短信
     *
     * @param mobile  手机号
     * @param type    类型
     * @param content 短信内容
     * @return {@link BaseResponse}
     */
    public BaseResponse sendSmsFree(String mobile, int type, String content) {
        BaseResponse response = verify(mobile, type);
        if (response.getCode() != BaseResponse.SUCCEED) {
            return response;
        }
        try {
            String smsSign;
            //根据type指定短信抬头
            switch (type) {
                case 1:
                    smsSign = "南方医务通";
                    break;
                default:
                    smsSign = "南方医务通";
                    break;
            }
            SendSMSFreeRequest req = SendSMSFreeRequest.newBuilder()
                    .setContent(content.trim())
                    .setPhoneNumbers(mobile)//手机号，多个手机号为用半角 , 分开，如13899999999,13688888888
                    .setSmsSign(smsSign)//短信抬头
                    .build();
            SendSMSFreeResponse res = smsServiceBlockingStub.sendSMSFree(req);
            if (res.getCode() == ResultCode.SUCCEED.getNumber()) {
                return response.succeed(res.getReturnContent());
            }
            return response.failed(BaseResponse.OTHER_ERROR, res.getReturnContent());
        } catch (Exception e) {
            logger.error(String.format("sendSmsFree(\"%s\", %s)", mobile, type), e);
            return response.failed(BaseResponse.APP_EXCEPTION, e.getMessage());
        }
    }

    /**
     * 判断该科室是否属于名医诊区（包括一级二级）
     *
     * @param deptCode 待判断科室
     * @return true or false
     */
    public boolean checkIsNetDept(String deptCode, int hospitalId) {
        HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
                .setHospitalId(hospitalId)
                .build();
        HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
        if (res.getResult().getCode() == ResultCode.SUCCEED) {
            List<HospitalDept> hospitalDepts = res.getHospitalDeptListList();
            List<String> netDeptIds = new LinkedList<>();
            if (!Checker.isNone(hospitalDepts)) {
                List<HospitalDept> hdList = hospitalDepts.stream()
                        .filter(hospitalDept -> BizUtil.getNetDeptCodeListByHospitalId(hospitalId).contains(hospitalDept.getDeptCode())).collect(Collectors.toList());
                for (HospitalDept hd : hdList) {
                    netDeptIds.add(hd.getDeptCode());
                    for (Dept sd : hd.getDeptListList()) {
                        netDeptIds.add(sd.getDeptCode());
                    }
                }
                return netDeptIds.stream().anyMatch(id -> id.equals(deptCode));
            }
        }
        return false;
    }

    /**
     * 只返回需要显示的医院（不带下级医院的医院，和分院）
     *
     * @param hospitalIds 一级医院IDs，eg:[12, 41]
     * @return {@link BaseResponse}
     */
    public BaseResponse getHospitalListByHospitalIds(List<Integer> hospitalIds) {
        BaseResponse response = new BaseResponse();
        if (Checker.isNone(hospitalIds)) {
            return response.failedWithParameterError("参数不能为空");
        }
        GetHospitalByHospitalIdsRequest req = GetHospitalByHospitalIdsRequest.newBuilder()
                .addAllHospitalId(hospitalIds)
                .build();
        GetHospitalByHospitalIdsResponse res = systemServiceBlockingStub.getHospitalByHospitalIds(req);
        if (res.getCode() != ResultCode.SUCCEED.getNumber()) {
            return response.failedWithParameterError(res.getMessage());
        }
        List<Map<String, Object>> list = new LinkedList<>();
        List<Hospital> hospitalList = res.getHospitalList();
        for (Hospital h : hospitalList) {
            // 这里只返回不带下级医院的医院(parentId = 0,且没有下级医院)，和分院(parentId > 0)
            long count = 0;
            // 这里采用排除法，带有下级医院的就一级医院就排除在外
            if (h.getParentId() == 0) {
                count = hospitalList.stream().filter(p -> h.getParentId() == p.getParentId()).count();
            }
            if (count == 0) {
                Map<String, Object> map = new HashMap<>();
                map.put("hospitalId", h.getHospitalId());
                map.put("hospitalName", h.getHospitalName());
                map.put("hospitalLogo", h.getLogo());
                map.put("address", h.getAddress());
                list.add(map);
            }
        }
        return response.succeed("处理成功", list);
    }

    /**
     * 根据 hospitalIds 获取医院或其分医院。如果医院有分院，则返回分院；如果无分院，返回该医院。
     */
    public BaseResponse getHospitalListByHospitalIdsNew(List<Integer> hospitalIds) {
        BaseResponse response = new BaseResponse();
        if (Checker.isNone(hospitalIds)) {
            return response.failedWithParameterError("参数不能为空");
        }
        GetHospitalByHospitalIdsRequest req = GetHospitalByHospitalIdsRequest.newBuilder()
                .addAllHospitalId(hospitalIds)
                .build();
        GetHospitalByHospitalIdsResponse res = systemServiceBlockingStub.getHospitalByHospitalIds(req);
        if (res.getCode() != ResultCode.SUCCEED.getNumber()) {
            return response.failedWithParameterError(res.getMessage());
        }
        List<Map<String, Object>> list = new LinkedList<>();
        List<Hospital> hospitalList = res.getHospitalList();
        List<Hospital> subHospList = hospitalList.stream().filter(h -> Checker.getIntegerValue(h.getParentId()) > 0).collect(Collectors.toList());
        Set<Integer> parentHospitalIds = subHospList.stream().map(h -> Checker.getIntegerValue(h.getParentId())).collect(Collectors.toSet());
        List<Hospital> filteredParentHospitalList = hospitalList.stream().filter(h -> Checker.getIntegerValue(h.getParentId()) == 0 && !parentHospitalIds.contains(h.getHospitalId())).collect(Collectors.toList());
        for (Hospital h : subHospList) {
            Map<String, Object> map = new HashMap<>();
            map.put("hospitalId", h.getParentId());
            map.put("subHospitalId", h.getHospitalId());
            map.put("hospitalName", h.getHospitalName());
            map.put("hospitalLogo", h.getLogo());
            map.put("address", h.getAddress());
            HospitalCustomInfo p  = BizUtil.getHospitalCustomInfo(h.getHospitalId());
            if (p != null) {
                map.put("alias", p.getAlias());
                map.put("areaName", p.getAreaName());
            }
            list.add(map);
        }
        for (Hospital h : filteredParentHospitalList) {
            Map<String, Object> map = new HashMap<>();
            map.put("hospitalId", h.getHospitalId());
            map.put("subHospitalId", 0);
            map.put("hospitalName", h.getHospitalName());
            map.put("hospitalLogo", h.getLogo());
            map.put("address", h.getAddress());
            HospitalCustomInfo p  = BizUtil.getHospitalCustomInfo(h.getHospitalId());
            if (p != null) {
                map.put("alias", p.getAlias());
                map.put("areaName", p.getAreaName());
            }
            list.add(map);
        }
        return response.succeed("处理成功", list);
    }

    public SearchDeptListByNameResponse searchDeptListByName(String key, int hospitalId) {
        SearchDeptListByNameRequest req = SearchDeptListByNameRequest.newBuilder()
                .setDeptName(key.trim())
                .setHospitalId(hospitalId)
                .build();
        return systemServiceBlockingStub.searchDeptListByName(req);
    }

    public SearchDoctorListByNameResponse searchDoctorListByName(String key, int hospitalId) {
        SearchDoctorListByNameRequest req = SearchDoctorListByNameRequest.newBuilder()
                .setDoctorName(key.trim())
                .setHospitalId(hospitalId)
                .build();
        return systemServiceBlockingStub.searchDoctorListByName(req);
    }

    public SearchDoctorListByNameResponse searchDoctorByNameFromMultiHosp(String key, List<Integer> hospitalIds) {
        SearchDoctorByNameFromMultiHospRequest req = SearchDoctorByNameFromMultiHospRequest.newBuilder()
                .setDoctorName(key.trim())
                .addAllHospitalId(hospitalIds)
                .build();
        return systemServiceBlockingStub.searchDoctorByNameFromMultiHosp(req);
    }
}
