package com.ywt.outpatient.controllers;

import com.fasterxml.jackson.databind.JsonNode;
import com.ywt.biz.common.exception.YwtCommonException;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.DateUtil;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.checkup_booking.*;
import com.ywt.gapi.taihe.outpaitent.GetMedicalCardInfoByPatientIdRequest;
import com.ywt.gapi.taihe.outpaitent.GetMedicalCardInfoByPatientIdResponse;
import com.ywt.gapi.taihe.outpaitent.TaiheOutpatientService;
import com.ywt.outpatient.api.checkup_booking.RegCheckupItemResp;
import com.ywt.outpatient.api.checkup_booking.SaveRegRecordResp;
import com.ywt.outpatient.api.req.*;
import com.ywt.outpatient.api.resp.*;
import com.ywt.outpatient.api.resp.CheckupItemCategory;
import com.ywt.outpatient.core.BaseResponse;
import com.ywt.outpatient.core.utils.AESUtil;
import com.ywt.outpatient.core.utils.BizUtil;
import com.ywt.outpatient.core.utils.CheckUtil;
import com.ywt.outpatient.core.utils.IdCardUtil;
import com.ywt.outpatient.service.web.UserSrv;
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.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 体检预约
 *
 * @author Walker
 * Created on 2022/4/27
 */

@RestController("/checkupBooking")
@RequestMapping(value = {"/checkupBooking"}, method = RequestMethod.POST)
public class CheckupBookingController {
    private final Logger logger = LoggerFactory.getLogger(CheckupBookingController.class);

    @Autowired
    private UserSrv userSrv;
    @DubboReference
    private CheckupBookingService bookingServiceBlockingStub;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @DubboReference
    private CheckupBookingRpcService bookingRpcServiceBlockingStub;
    @DubboReference
    private TaiheOutpatientService taiheOutpatientServiceBlockingStub;

    public static final String PM_TYPE_INDIVIDUAL = "I"; // 预约类型：个人

    // 所有加项缓存 redis key，后缀 医院 id + locId
    public static final String RK_ALL_ITEM_LIST = "wapapi:checkup_booking_all_item_list_%d_%s";
    // 所有加项缓存时间
    public static final int ALL_ITEM_LIST_CACHE_TIME_IN_SECOND = 30 * 60; // 30 分钟

    //取消订单状态
    private static final String CancelStatus = "6";

    // 获取套餐类型列表
    @RequestMapping(value = {"/queryPackageLevelList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetPackageLevelListResp>> queryPackageLevelList(@RequestBody GetPackageLevelListReq reqData) {
        BaseResponse2<ListResponse<GetPackageLevelListResp>> baseResponse = new BaseResponse2<>();
        try {
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            GetPackageLevelListResponse response = bookingServiceBlockingStub.getPackageLevelList(GetPackageLevelListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setLocId(locId)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<GetPackageLevelListResp> resp = new ListResponse<>();
                resp.setList(response.getPackageLevelList().stream()
                        .map(i -> {
                            GetPackageLevelListResp r = new GetPackageLevelListResp();
                            r.setLevelId(i.getLevelId());
                            r.setLevelDesc(i.getLevelDesc());
                            return r;
                        })
                        .collect(Collectors.toList()));
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#queryPackageLevelList(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    // 获取套餐列表接口
    @RequestMapping(value = {"/queryPackageList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetPackageListResp>> queryPackageList(@RequestBody GetPackageListReq reqData) {
        BaseResponse2<ListResponse<GetPackageListResp>> baseResponse = new BaseResponse2<>();
        try {
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String levelId = Checker.getStringValue(reqData.getLevelId());
            String sexDesc = Checker.getStringValue(reqData.getSexDesc());
            GetPackageListResponse response = bookingServiceBlockingStub.getPackageList(GetPackageListRequest.newBuilder()
                    .setLocId(locId)
                    .setHospitalId(hospitalId)
                    .setLevelId(levelId)
                    .setSexDesc(sexDesc)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<GetPackageListResp> resp = new ListResponse<>();
                resp.setList(response.getPackageList().stream().map(p -> {
                    GetPackageListResp r = new GetPackageListResp();
                    r.setPackageId(p.getPackageId());
                    r.setPackageDesc(p.getPackageDesc());
                    r.setPackageAmt(p.getPackageAmt());
                    r.setOrdSetsId(p.getOrdSetsId());
                    r.setLevelDesc(p.getLevelDesc());
                    r.setLevelId(p.getLevelId());
                    r.setGiFlag(p.getGiFlag());
                    r.setSexDesc(p.getSexDesc());
                    r.setOrdSetsType(p.getOrdSetsType());
                    r.setLocId(p.getLocId());
                    r.setLocDesc(p.getLocDesc());
                    r.setOriginAmt(p.getOriginAmt());
                    r.setSort(p.getSort());
                    return r;
                })
                        .collect(Collectors.toList()));
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#queryPackageList(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    // 获取套餐明细列表
    @RequestMapping(value = {"/getPackageItemList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetPackageItemListResp>> getPackageItemList(@RequestBody GetPackageItemListReq reqData) {
        BaseResponse2<ListResponse<GetPackageItemListResp>> baseResponse = new BaseResponse2<>();
        try {
            String ordSetsId = reqData.getOrdSetsId();
            CheckUtil.ensureNotEmpty(ordSetsId, "套餐代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            GetPackageItemListResponse response = bookingServiceBlockingStub.getPackageItemList(GetPackageItemListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setOrdSetsId(ordSetsId)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<GetPackageItemListResp> resp = new ListResponse<>();
                resp.setList(response.getPackageItemList().stream().map(i -> {
                    GetPackageItemListResp r = new GetPackageItemListResp();
                    r.setItemCategoryId(i.getItemCategoryId());
                    r.setItemCategoryDesc(i.getItemCategoryDesc());
                    r.setHisItemId(i.getHisItemId());
                    r.setItemDesc(i.getItemDesc());
                    r.setPrice(i.getPrice());
                    return r;
                })
                        .collect(Collectors.toList()));
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getPackageItemList(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    // 获取所有检查加项，分组
    @RequestMapping(value = {"/getAllItemList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<CheckupItemCategory>> getAllItemList(@RequestBody GetAllItemListReq reqData) {
        BaseResponse2<ListResponse<CheckupItemCategory>> baseResponse = new BaseResponse2<>();
        try {
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String keyword = Checker.getStringValue(reqData.getKeyword());
            List<CheckupItemResp> list = new ArrayList<>();
            // 获取加项数据
            // 先从缓存读取
            String rk = String.format(RK_ALL_ITEM_LIST, hospitalId, locId);
            String value = redisTemplate.opsForValue().get(rk)+"";
            if (!StringHelper.isNullOrWhiteSpace(value)) {
                JsonNode jn = JsonSerializer.readToNode(value);
                if (jn != null && jn.isArray()) {
                    for (JsonNode n : jn) {
                        CheckupItemResp r = JsonSerializer.from(n.toString(), CheckupItemResp.class);
                        if (r != null) {
                            list.add(r);
                        }
                    }
                }
            }
            if (Checker.isNone(list)) {
                logger.info("CheckupBookingController#getAllItemList(rk = {}): 缓存获取不到数据", rk);
                // 从 HIS 接口读取
                GetAllItemListResponse response = bookingServiceBlockingStub.getAllItemList(GetAllItemListRequest.newBuilder()
                        .setHospitalId(hospitalId)
                        .setLocId(locId)
                        .setKeyword(keyword)
                        .build());
                if (response.getCode() != BaseResponse.SUCCEED) {
                    return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
                }
                list = response.getCheckupItemList().stream().map(i -> {
                    CheckupItemResp r = new CheckupItemResp();
                    r.setItemCategoryDesc(i.getItemCategoryDesc());
                    r.setItemCategoryId(i.getItemCategoryId());
                    r.setHisItemId(i.getHisItemId());
                    r.setItemDesc(i.getItemDesc());
                    r.setPrice(i.getPrice());
                    return r;
                }).collect(Collectors.toList());
                // 存入缓存
                redisTemplate.opsForValue().set(rk, JsonSerializer.toJson(list), ALL_ITEM_LIST_CACHE_TIME_IN_SECOND, TimeUnit.SECONDS);
            }
            // 搜索过滤
            if (!StringHelper.isNullOrWhiteSpace(keyword)) {
                list = list.stream().filter(i -> Checker.getStringValue(i.getItemDesc()).contains(keyword)).collect(Collectors.toList());
            }
            // 分组
            List<CheckupItemCategory> categoryList = new ArrayList<>();
            Map<String, List<CheckupItemResp>> map = list.stream()
                    .collect(Collectors.groupingBy(CheckupItemResp::getItemCategoryId));
            for (String k : map.keySet()) {
                CheckupItemCategory c = new CheckupItemCategory();
                List<CheckupItemResp> l = map.get(k);
                CheckupItemResp item = Checker.isNone(l) ? null : l.get(0);
                c.setItemCategoryDesc(item == null ? "" : Checker.getStringValue(item.getItemCategoryDesc()));
                c.setItemCategoryId(k);
                // 移除不需要返回的字段
                l.forEach(i -> {
                    i.setItemCategoryId(null);
                    i.setItemCategoryDesc(null);
                });
                c.setList(l);
                categoryList.add(c);
            }
            ListResponse<CheckupItemCategory> resp = new ListResponse<>();
            resp.setList(categoryList);
            return baseResponse.succeed(resp);
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getAllItemList(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    // 查询某段时间内可预约日期及限额信息
    @RequestMapping(value = {"/getRegInfoList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetRegInfoListResp>> getRegInfoList(@RequestBody GetRegInfoListReq reqData) {
        BaseResponse2<ListResponse<GetRegInfoListResp>> baseResponse = new BaseResponse2<>();
        try {
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String sex = Checker.getStringValue(reqData.getSex());
            CheckUtil.ensureNotEmpty(sex, "性别不能为空");
            String levelDesc = Checker.getStringValue(reqData.getLevelDesc());
            CheckUtil.ensureNotEmpty(levelDesc, "等级描述不能为空");
            String startExamDate = Checker.getStringValue(reqData.getStartExamDate());
            CheckUtil.ensureNotEmpty(startExamDate, "开始日期不能为空");
            String endExamDate = Checker.getStringValue(reqData.getEndExamDate());
            CheckUtil.ensureNotEmpty(endExamDate, "结束日期不能为空");
            Date date = DateUtil.parseDate(startExamDate, "yyyy-MM-dd");
            if (date == null) {
                return baseResponse.failedWithParameterError("开始日期格式不正确");
            }
            date = DateUtil.parseDate(endExamDate, "yyyy-MM-dd");
            if (date == null) {
                return baseResponse.failedWithParameterError("结束日期格式不正确");
            }
            String pmType = Checker.getStringValue(reqData.getPmType(), PM_TYPE_INDIVIDUAL);
            GetRegInfoListResponse response = bookingServiceBlockingStub.getRegInfoList(GetRegInfoListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setLocId(locId)
                    .setSex(sex)
                    .setStartExamDate(startExamDate)
                    .setEndExamDate(endExamDate)
                    .setPmType(pmType)
                    .setLevelDesc(levelDesc)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<GetRegInfoListResp> resp = new ListResponse<>();
                resp.setList(response.getRegInfoList().stream()
                        // 过滤不可约或已过期的
                        .filter(i -> i.getAvailRegCount() > 0)
                        .map(i -> {
                            GetRegInfoListResp r = new GetRegInfoListResp();
                            r.setExamDate(i.getExamDate());
//                            r.setExamLocDesc(i.getExamLocDesc());
//                            r.setExamLocId(i.getExamLocId());
//                            r.setAvailRegCount(i.getAvailRegCount());
//                            r.setRegCount(i.getRegCount());
//                            r.setTotalCount(i.getTotalCount());
                            r.setStrId(i.getStrId());
//                            r.setOtherLocId(i.getOtherLocId());
//                            r.setStatus(i.getStatus());
//                            r.setDatePmType(i.getDatePmType());
                            return r;
                        })
                        .collect(Collectors.toList()));
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getRegInfoList(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    //获取检查须知
    @RequestMapping(value = {"/getAnnouncement"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<CheckupBookingAnnouncementResp> getAnnouncement(@RequestBody CheckupBookAnnounceReq req) {
        BaseResponse2<CheckupBookingAnnouncementResp> response = new BaseResponse2<>();
        try {
            int hospitalId = Checker.getIntegerValue(req.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            GetAnnouncementResponse resp = bookingRpcServiceBlockingStub.getAnnouncement(GetAnnouncementRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .build());
            if (resp.getCode() == BaseResponse.SUCCEED) {
                CheckupBookingAnnouncementResp res = new CheckupBookingAnnouncementResp();
                res.setTitle(resp.getTitle());
                res.setContent(resp.getContent());
                return response.succeed(res);
            }
            return response.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getAnnouncemnt(): {}", e.getMessage(), e);
            return response.error(e.getMessage());
        }
    }

    //删除检查预约
    @RequestMapping(value = {"/cancelReg"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<CancelRegResp> cancelReg(@RequestBody CancelRegReq req) {
        BaseResponse2<CancelRegResp> response = new BaseResponse2<>();
        try {
            int userId = userSrv.getCurrentUserIdWrapped();
            if (userId <= 0) {
                CheckUtil.ensureLargerThanZero(userId, "请登录后操作");
            }
            String regId = req.getRegId();
            CheckUtil.ensureNotEmpty(regId, "网上预约记录ID不能为空");
            String encryptDataHex = req.getIdCard();
            CheckUtil.ensureNotEmpty(encryptDataHex, "身份证号不能为空");
            String idCard = AESUtil.decrypt(encryptDataHex);
            int hospitalId = Checker.getIntegerValue(req.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }

            CancelOrderResponse cancelOrderResponse = bookingRpcServiceBlockingStub.cancelOrder(CancelRegRequest.newBuilder()
                    .setRegId(regId)
                    .setIdCard(idCard)
                    .setHospitalId(hospitalId)
                    .build());
            if (cancelOrderResponse.getCode() != BaseResponse.SUCCEED) {
                logger.error("CheckupBookingController#cancelReg(): {}", cancelOrderResponse.getInfo());

            }
            return response.succeed();

        } catch (YwtCommonException appMessageException) {
            return response.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#cancelReg(): {}", e.getMessage(), e);
            return response.error(e.getMessage());
        }

    }

    /**
     * 将性别汉字转换为 HIS 指定的性别字母
     */
    private String genderHanziConvert2Letter(String hanzi) {
        switch (hanzi) {
            case "男":
                return "M";
            case "女":
                return "F";
            default:
                return "";
        }
    }

    // 提交预约记录
    @RequestMapping(value = {"/saveRegRecord"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<SaveRegRecordResp> saveRegRecord(@RequestBody SaveRegRecordReq reqData) {
        BaseResponse2<SaveRegRecordResp> baseResponse = new BaseResponse2<>();
        try {
            int userId = userSrv.getCurrentUserIdWrapped();
            if (userId <= 0) {
                CheckUtil.ensureLargerThanZero(userId, "请登录后操作");
            }
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            String hisPatientId = reqData.getHisPatientId();
            CheckUtil.ensureNotEmpty(hisPatientId, "HIS 患者 ID 不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            // 获取身份证和姓名
            GetMedicalCardInfoByPatientIdRequest gResp = GetMedicalCardInfoByPatientIdRequest.newBuilder()
                    .setHisPatientId(hisPatientId)
                    .setHospitalId(hospitalId)
                    .setUserId(userSrv.getCurrentUserIdWrapped())
                    .build();
            GetMedicalCardInfoByPatientIdResponse gmcResp = taiheOutpatientServiceBlockingStub.getMedicalCardInfoByPatientId(gResp);
            if (gmcResp.getCode() != ResultCode.SUCCEED_VALUE) {
                return baseResponse.failedWithAppError(String.format("获取不到诊疗卡信息: %s(%s)", gmcResp.getMsg(), hisPatientId));
            }
            // 从诊疗卡获取患者信息
            String certificateNo = gmcResp.getIdNo();
            String patientName = gmcResp.getPatientName();
            String telephoneNo = gmcResp.getMobile();
            String patientDob = gmcResp.getBirthday();
            String sex = genderHanziConvert2Letter(IdCardUtil.getSex(gmcResp.getIdNo()));
            String medCardNo = gmcResp.getCardNo();

            String pmType = Checker.getStringValue(reqData.getPmType(), PM_TYPE_INDIVIDUAL);
            String levelDesc = reqData.getLevelDesc();
            CheckUtil.ensureNotEmpty(levelDesc, "套餐等级描述不能为空");
            String ordSetsId = reqData.getOrdSetsId();
            CheckUtil.ensureNotEmpty(ordSetsId, "套餐 id 不能为空");
            String examDate = reqData.getExamDate();
            Date date = DateUtil.parseDate(examDate, "yyyy-MM-dd");
            if (date == null) {
                return baseResponse.failedWithParameterError("日期格式不正确");
            }
            CheckUtil.ensureNotEmpty(examDate, "预约日期不能为空");
            String detailId = reqData.getDetailId();
            CheckUtil.ensureNotEmpty(detailId, "排班 id 不能为空");
            List<SelfItemReq> selfItemList = new ArrayList<>();
            if (!Checker.isNone(reqData.getSelfItemList())) {
                selfItemList = reqData.getSelfItemList();
            }
            SaveRegRecordResponse response = bookingServiceBlockingStub.saveRegRecord(SaveRegRecordRequest.newBuilder()
                    .setCertificateNo(certificateNo)
                    .setPatientName(patientName)
                    .setTelephoneNo(telephoneNo)
                    .setPatientDob(patientDob)
                    .setSex(sex)
                    .setLocId(locId)
                    .setPmType(pmType)
                    .setLevelDesc(levelDesc)
                    .setOrdSetsId(ordSetsId)
                    .setExamDate(examDate)
                    .setDetailId(detailId)
                    .addAllSelfItem(selfItemList.stream().map(i -> SelfItem.newBuilder()
                            .setItemId(Checker.getStringValue(i.getItemId()))
                            .build()
                    ).collect(Collectors.toList()))
                    .setHospitalId(hospitalId)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                SaveRegRecordResp resp = new SaveRegRecordResp();
                RegRecord record = response.getRegRecord();
                resp.setPatientRegNo(record.getPatientRegNo());
                resp.setPatientName(record.getPatientName());
                resp.setSex(record.getSex());
                resp.setPatientAge(record.getPatientAge());
                resp.setPatientIdNo(BizUtil.maskedIdCardNo(record.getPatientIdNo()));
                resp.setPatientIdNoEncrypt(AESUtil.encrypt(record.getPatientIdNo()));
                resp.setRegId(record.getRegId());
                resp.setPhoneNo(record.getPhoneNo());
                resp.setLevelDesc(record.getLevelDesc());
                resp.setTotalAmount(record.getTotalAmount());
                resp.setStatus(record.getStatus());
                resp.setPayFlag(record.getPayFlag());
                resp.setAdmId(record.getAdmId());
                resp.setPreIADM(record.getPreIADM());
                resp.setLocId(record.getLocId());
                resp.setLocDesc(record.getLocDesc());
                resp.setRegExamDate(record.getRegExamDate());
                resp.setRegExamTime(record.getRegExamTime());
                resp.setPmType(record.getPmType());
                resp.setPeId(record.getPeId());
                resp.setCanModifyFlag(record.getCanModifyFlag());
                resp.setPreWay(record.getPreWay());
                // 获取套餐详情，根据套餐内项目判断 HIS 预约成功后返回的项目列表哪些是加项的（包括用户手动加项和 HIS 系统自动加项）
                GetPackageItemListResponse packListResp = bookingServiceBlockingStub.getPackageItemList(GetPackageItemListRequest.newBuilder()
                        .setHospitalId(hospitalId)
                        .setOrdSetsId(ordSetsId)
                        .build());
                List<String> inPackageHisItemIds = packListResp.getCode() == BaseResponse.SUCCEED ?
                        packListResp.getPackageItemList().stream().map(PackageItem::getHisItemId).collect(Collectors.toList()) :
                        new ArrayList<>();
                if (packListResp.getCode() != BaseResponse.SUCCEED) {
                    logger.error("CheckupBookingController#saveRegRecord(ordSetsId={} ):\n 获取套餐详情失败！{}", ordSetsId, packListResp.getInfo());
                }
                resp.setRegCheckupItemRespList(record.getRegCheckupItemList().stream().map(i -> {
                    RegCheckupItemResp r = new RegCheckupItemResp();
                    r.setItemId(i.getItemId());
                    r.setItemDesc(i.getItemDesc());
                    r.setPreIOrdDr(i.getPreIOrdDr());
                    r.setNetPreItemDr(i.getNetPreItemDr());
                    r.setOrdSetsDr(i.getOrdSetsDr());
                    r.setOrdSetsDesc(i.getOrdSetsDesc());
                    r.setItemCategoryDesc(i.getItemCategoryDesc());
                    r.setPrice(i.getPrice());
                    r.setInPackage(inPackageHisItemIds.contains(i.getItemId()));
                    return r;
                }).collect(Collectors.toList()));
                // 取 HIS 预约成功后返回的 RegCheckupItemList 第一个元素中的 OrdSetsDesc 返回给前端显示
                RegCheckupItem regCheckupItem = record.getRegCheckupItemList().stream().findFirst().orElse(null);
                String ordSetsDesc = regCheckupItem == null ? "" : Checker.getStringValue(regCheckupItem.getOrdSetsDesc());
                resp.setOrdSetsDesc(ordSetsDesc);

                CreateOrderResponse createOrderResponse = bookingRpcServiceBlockingStub.createOrder(CreateOrderRequest.newBuilder()
                        .setRegRecord(record.toBuilder()
                                .clearRegCheckupItem()
                                .addAllRegCheckupItem(record.getRegCheckupItemList().stream()
                                        .map(i -> i.toBuilder().setInPackage(inPackageHisItemIds.contains(i.getItemId())).build())
                                        .collect(Collectors.toList()))
                                .build())
                        .setUserId(userId)
                        .setHospitalId(hospitalId)
                        .setMedCardNo(medCardNo)
                        .build());
                resp.setOrderNo(createOrderResponse.getOrderNo());
                resp.setCreateTime(createOrderResponse.getCreateTime());
                if (createOrderResponse.getCode() != BaseResponse.SUCCEED) {
                    logger.error("CheckupBookingController#saveRegRecord(userId = {}, regId = {}): 创建订单失败！{}",
                            userId, record.getRegId(), createOrderResponse.getInfo());
                }
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#saveRegRecord(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    //查询某一天的时段限额信息
    @RequestMapping(value = {"/getDateRegInfo"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetDateRegInfoResp>> getDateRegInfo(@RequestBody GetDateRegInfoReq req) {
        BaseResponse2<ListResponse<GetDateRegInfoResp>> baseResponse = new BaseResponse2<>();
        try {
            String locId = req.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(req.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String sex = req.getSex();
            CheckUtil.ensureNotEmpty(sex, "性别不能为空");
            String levelDesc = Checker.getStringValue(req.getLevelDesc());
            String strId = Checker.getStringValue(req.getStrId());
            CheckUtil.ensureNotEmpty(strId, "日期排班ID不能为空");
            String pmType = Checker.getStringValue(req.getPmType(), PM_TYPE_INDIVIDUAL);
            String datePmType = Checker.getStringValue(req.getDatePmType(), PM_TYPE_INDIVIDUAL);
            GetDateRegInfoResponse response = bookingServiceBlockingStub.getDateRegInfo(GetDateRegInfoRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setLocId(locId)
                    .setLevelDesc(levelDesc)
                    .setSex(sex)
                    .setStrId(strId)
                    .setPmType(pmType)
                    .setDatePmType(datePmType)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<GetDateRegInfoResp> resp = new ListResponse<>();
                resp.setList(response.getDateRegInfoList().stream()
                        //过滤没有号原的时间段
                        .filter(i -> i.getAvailRegCount() > 0)
                        .map(i -> {
                            GetDateRegInfoResp r = new GetDateRegInfoResp();
                            r.setSex(i.getSex());
                            r.setAvailRegCount(i.getAvailRegCount());
                            r.setStartTime(i.getStartTime());
                            r.setEndTime(i.getEndTime());
                            r.setDetailId(i.getDetailId());
                            r.setDatePmType(i.getStartTime());
                            return r;
                        }).collect(Collectors.toList()));
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#(): getDateRegInfo{}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    //获取预约记录
    @RequestMapping(value = {"/getRegRecordList"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<SaveRegRecordResp>> getRegRecordList(@RequestBody GetRegRecordListReq req) {
        BaseResponse2<ListResponse<SaveRegRecordResp>> baseResponse = new BaseResponse2<>();
        try {
            int userId = userSrv.getCurrentUserIdWrapped();
            if (userId <= 0) {
                CheckUtil.ensureLargerThanZero(userId, "请登录后操作");
            }
            int hospitalId = Checker.getIntegerValue(req.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String preId = Checker.getStringValue(req.getPeId());
            String patientIdNoEncrypt = Checker.getStringValue(req.getPatientIdNo());
            String patientIdNo = AESUtil.decrypt(patientIdNoEncrypt);
            CheckUtil.ensureNotEmpty(patientIdNo, "身份证号不能为空");
            String payFlag = Checker.getStringValue(req.getPayFlag());
            CheckUtil.ensureNotEmpty(payFlag, "缴费标志不能为空");
            GetRegRecordListResponse response = bookingServiceBlockingStub.getRegRecordList(GetRegRecordListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setPatientIdNo(patientIdNo)
                    .setPayFlag(payFlag)
                    .build());
            GetOrderListResponse reponse = bookingRpcServiceBlockingStub.getOrderList(GetOrderListRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setIdCard(patientIdNo)
                    .build());
            List<OrderItem> ls = reponse.getOrderItemList();
            if (response.getCode() == BaseResponse.SUCCEED) {
                ListResponse<SaveRegRecordResp> resp = new ListResponse<>();
                List<SaveRegRecordResp> lss = response.getRegRecordList().stream()
                        .map(i -> {
                            SaveRegRecordResp r = new SaveRegRecordResp();
                            r.setPatientRegNo(i.getPatientRegNo());
                            r.setPatientName(i.getPatientName());
                            r.setSex(i.getSex());
                            r.setPatientAge(i.getPatientAge());
                            r.setPatientIdNo(BizUtil.maskedIdCardNo(i.getPatientIdNo()));
                            r.setPatientIdNoEncrypt(AESUtil.encrypt(i.getPatientIdNo()));
                            r.setRegId(i.getRegId());
                            r.setPhoneNo(i.getPhoneNo());
                            r.setLevelDesc(i.getLevelDesc());
                            r.setStatus(i.getStatus());
                            r.setPayFlag(i.getPayFlag());
                            r.setAdmId(i.getAdmId());
                            r.setPreIADM(i.getPreIADM());
                            r.setLocId(i.getLocId());
                            r.setLocDesc(i.getLocDesc());
                            r.setRegExamDate(i.getRegExamDate());
                            r.setRegExamTime(i.getRegExamTime());
                            r.setPmType(i.getPmType());
                            r.setPeId(i.getPeId());
                            r.setCanModifyFlag(i.getCanModifyFlag());
                            r.setPreWay(i.getPreWay());
                            OrderItem orItem = ls.stream().filter(item -> item.getRegId().equals(i.getRegId())).findFirst().orElse(null);
                            if (!Checker.isNone(orItem)) {
                                if (i.getStatus().equals(CancelStatus)) {
                                    r.setTotalAmount(orItem.getTotalPrice());
                                } else {
                                    r.setTotalAmount(i.getTotalAmount());
                                }
                                r.setCreateTime(orItem.getCreateTime());
                                r.setOrderNo(orItem.getOrderNo());
                                String regCheckup = orItem.getRegCheckupItems();
                                List<RegCheckupItemResp> regCheckupItemResList = new ArrayList<>();
                                if (!StringHelper.isNullOrWhiteSpace(regCheckup)) {
                                    JsonNode jn = JsonSerializer.readToNode(regCheckup);
                                    if (jn != null && jn.isArray()) {
                                        for (JsonNode n : jn) {
                                            RegCheckupItemResp c = JsonSerializer.from(n.toString(), RegCheckupItemResp.class);
                                            if (c != null) {
                                                regCheckupItemResList.add(c);
                                            }
                                        }
                                    }
                                }
                                r.setRegCheckupItemRespList(regCheckupItemResList);
                            }
                            String ordSetsDesc = "";
                            if (r.getRegCheckupItemRespList() != null) {
                                // 取 HIS 预约成功后返回的 RegCheckupItemList 第一个元素中的 OrdSetsDesc 返回给前端显示
                                RegCheckupItemResp regCheckupItem = r.getRegCheckupItemRespList().stream().findFirst().orElse(null);
                                ordSetsDesc = regCheckupItem == null ? "" : Checker.getStringValue(regCheckupItem.getOrdSetsDesc());
                            }
                            r.setOrdSetsDesc(ordSetsDesc);
                            return r;
                        }).sorted(((o1, o2) -> {
                            Integer a = getNumberFromStr(o1.getRegId());
                            Integer b = getNumberFromStr(o2.getRegId());
                            return b.compareTo(a);
                        })).collect(Collectors.toList());
                resp.setList(lss);
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#(): getRegRecordList{}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }


    private int getNumberFromStr(String str) {
        if (StringHelper.isNullOrEmpty(str)) return 0;
        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException e) {
            logger.error("NfyyByfyRegisterController#subSpecialityList(): {}", e.getMessage(), e);
            return 0;
        }
    }

    // 根据身份证号查询未检记录
    @RequestMapping(value = {"/getUncheckedRecord"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<ListResponse<GetUncheckedRecordResp>> getUncheckedRecord(@RequestBody GetUncheckedRecordReq reqData) {
        BaseResponse2<ListResponse<GetUncheckedRecordResp>> baseResponse = new BaseResponse2<>();
        try {
            int userId = userSrv.getCurrentUserIdWrapped();
            if (userId <= 0) {
                CheckUtil.ensureLargerThanZero(userId, "请登录后操作");
            }
            String locId = reqData.getLocId();
            CheckUtil.ensureNotEmpty(locId, "科室代码不能为空");
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            String encryptDataHex = reqData.getIdCardNo();
            String idCardNo = AESUtil.decrypt(encryptDataHex);
            logger.error("getUncheckedRecord>>encryptDataHex:{},\tidCardNo:{}", encryptDataHex, idCardNo);
            GetUncheckedRecordResponse response = bookingServiceBlockingStub.getUncheckedRecord(GetUncheckedRecordRequest.newBuilder()
                    .setHospitalId(hospitalId)
                    .setLocId(locId)
                    .setIdCardNo(idCardNo)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                List<GetUncheckedRecordResp> list = response.getUncheckRecordList().stream().map(r -> {
                    GetUncheckedRecordResp resp = new GetUncheckedRecordResp();
                    resp.setPatientRegNo(r.getPatientRegNo());
                    resp.setPatientName(r.getPatientName());
                    resp.setSex(r.getSex());
                    resp.setPatientAge(r.getPatientAge());
                    resp.setPatientIdNo(r.getPatientIdNo());
                    resp.setRegId(r.getRegId());
                    resp.setPhoneNo(r.getPhoneNo());
                    resp.setLevelDesc(r.getLevelDesc());
                    resp.setTotalAmount(r.getTotalAmount());
                    resp.setAdmId(r.getAdmId());
                    resp.setPreIADM(r.getPreIADM());
                    resp.setLocId(r.getLocId());
                    resp.setRegExamDate(r.getRegExamDate());
                    resp.setPmType(r.getPmType());
                    resp.setPeId(r.getPeId());
                    resp.setPeStatus(r.getPeStatus());
                    resp.setCompanyDesc(r.getCompanyDesc());
                    resp.setIdCard(BizUtil.maskedIdCardNo(r.getIdCard()));
                    resp.setUncheckedItemInfoList(r.getUncheckedItemInfoList().stream().map(i -> {
                        UncheckedItemInfoResp ir = new UncheckedItemInfoResp();
                        ir.setGroupCode(i.getGroupCode());
                        ir.setGroupName(i.getGroupName());
                        ir.setLimitAmt(i.getLimitAmt());
                        ir.setTeamId(i.getTeamId());
                        ir.setTeamDesc(i.getTeamDesc());
                        ir.setStartDate(i.getStartDate());
                        ir.setEndDate(i.getEndDate());
                        ir.setLinkUser(i.getLinkUser());
                        ir.setLinkTelphone(i.getLinkTelphone());
                        return ir;
                    }).collect(Collectors.toList()));
                    return resp;
                })
                        .collect(Collectors.toList());
                ListResponse<GetUncheckedRecordResp> listResponse = new ListResponse<>();
                listResponse.setList(list);
                return baseResponse.succeed(listResponse);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (YwtCommonException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getUncheckedRecord(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    //获取套餐须知
    @RequestMapping(value = {"/getPackageNotice"}, method = RequestMethod.POST)
    public @ResponseBody
    BaseResponse2<CheckingBookingNoticeResp> getNotice(@RequestBody CheckupBookingNoticeReq req) {
        BaseResponse2<CheckingBookingNoticeResp> response = new BaseResponse2<>();
        try {
            int hospitalId = Checker.getIntegerValue(req.getHospitalId());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(userSrv.getCurrentTerminal());
            }
            GetNoticeResponse resp = bookingRpcServiceBlockingStub.getPackageNotice(GetNoticeRequest.newBuilder()
                    .setOrdSetsId(req.getOrdSetsId())
                    .setHospitalId(hospitalId)
                    .build());
            if (resp.getCode() == BaseResponse.SUCCEED) {
                CheckingBookingNoticeResp res = new CheckingBookingNoticeResp();
                res.setNotice(Checker.getStringValue(resp.getNotice()));
                res.setShow(Checker.getIntegerValue(resp.getShow()));
                return response.succeed(res);
            }
            return response.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (Exception e) {
            logger.error("CheckupBookingController#getPackageNotice(): {}", e.getMessage(), e);
            return response.error(e.getMessage());
        }
    }
}
