package com.ywt.outpatient.controllers;

import com.ywt.biz.common.enums.PaymentChannelEnum;
import com.ywt.biz.common.enums.SexEnum;
import com.ywt.biz.common.enums.TerminalEnum;
import com.ywt.biz.common.util.Checker;
import com.ywt.biz.common.util.DateUtil;
import com.ywt.biz.common.util.StringHelper;
import com.ywt.gapi.Result;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.offline.CreateOfflineConsultationRequest;
import com.ywt.gapi.offline.CreateOfflineConsultationResponse;
import com.ywt.gapi.offline.OfflineConsultingService;
import com.ywt.gapi.taihe.register.*;
import com.ywt.gapi.user.GetOfficialUserInfoRequest;
import com.ywt.gapi.user.GetOfficialUserInfoResponse;
import com.ywt.gapi.user.UserService;
import com.ywt.outpatient.api.req.CalAdditionalFeeReq;
import com.ywt.outpatient.api.resp.CalAdditionalFeeResp;
import com.ywt.outpatient.core.BaseResponse;
import com.ywt.outpatient.core.utils.BizUtil;
import com.ywt.outpatient.core.utils.CheckUtil;
import com.ywt.outpatient.domain.models.enums.DatePeriodEnum;
import com.ywt.outpatient.domain.models.enums.OfflineConsultationSourceEnum;
import com.ywt.outpatient.service.web.SystemSrv;
import com.ywt.outpatient.service.web.UserSrv;
import com.ywt.outpatient.core.WebAppContext;
import com.ywt.outpatient.service.web.patient.WebUserService;
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.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * 太和医院挂号 Controller
 *
 * @author johnson lin
 */
@RestController("/taihe/register/v2")
@RequestMapping(value = {"/taihe/register"}, method = RequestMethod.POST)
public class TaiheRegisterController {
    private static Logger logger = LoggerFactory.getLogger(TaiheRegisterController.class);

    @DubboReference
    private OfflineConsultingService offlineConsultingServiceBlockingStub;

    @DubboReference
    private TaiheRegisterService taiheRegisterServiceBlockingStub;

    @DubboReference
    private UserService userServiceBlockingStub;

    @Autowired
    private UserSrv userSrv;

    @Autowired
    private SystemSrv systemSrv;

    @Autowired
    private WebUserService userService;

    /**
     * 挂号
     * <p>
     * reqBody -> hospitalId       医院Id
     * reqBody -> deptCode         科室Code
     * reqBody -> deptName         科室名称
     * reqBody -> doctorCode       医生Code
     * reqBody -> doctorName       医生名称
     * reqBody -> registeredFee    挂号费
     * reqBody -> medicalFee       诊查费
     * reqBody -> registeredDate   预约日期
     * reqBody -> period           预约时间段
     * reqBody -> startTime        预约开始时间：HH:MI
     * reqBody -> endTime          预约结束时间：HH:MI
     * reqBody -> medicalCardId    就诊人Id
     * reqBody -> scheduleItemCode 门诊排班项记录标识
     *
     * @param reqBody 入参
     * @return
     */
    @RequestMapping({"/create"})
    public BaseResponse create(@RequestBody Map<String, Object> reqBody) {
        BaseResponse response = new BaseResponse();
        Integer hospitalId = (Integer) reqBody.getOrDefault("hospitalId", 0);
        String deptCode = (String) reqBody.getOrDefault("deptCode", "");
        String deptName = (String) reqBody.getOrDefault("deptName", "");
        String doctorCode = (String) reqBody.getOrDefault("doctorCode", "");
        String doctorName = (String) reqBody.getOrDefault("doctorName", "");
        Integer registeredFee = (Integer) reqBody.getOrDefault("registeredFee", 0);
        Integer medicalFee = (Integer) reqBody.getOrDefault("medicalFee", 0);
        String registeredDate = (String) reqBody.getOrDefault("registeredDate", "");
        Integer period = (Integer) reqBody.getOrDefault("period", 0);
        String startTime = (String) reqBody.getOrDefault("startTime", "");
        String endTime = (String) reqBody.getOrDefault("endTime", "");
        Integer medicalCardId = (Integer) reqBody.getOrDefault("medicalCardId", 0);
        String scheduleItemCode = (String) reqBody.getOrDefault("scheduleItemCode", "");
        Integer deptId = (Integer) reqBody.getOrDefault("deptId", 0);
        String lockQueueNo = (String) reqBody.getOrDefault("lockQueueNo", "");
        String availableNumStr = (String) reqBody.getOrDefault("availableNumStr", "");
        String doctorSessTypeCode = (String) reqBody.getOrDefault("doctorSessTypeCode", "");
        String doctorSessTypeName = (String) reqBody.getOrDefault("doctorSessTypeName", "");
        int subHospitalId = Checker.getIntegerValue((Integer) reqBody.getOrDefault("subHospitalId", 0));

        if (hospitalId < 1) {
            return response.failedWithParameterError("医院不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(deptCode) || StringHelper.isNullOrWhiteSpace(deptName)) {
            return response.failedWithParameterError("科室不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(doctorCode) || StringHelper.isNullOrWhiteSpace(doctorName)) {
            return response.failedWithParameterError("医生不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(registeredDate)) {
            return response.failedWithParameterError("请选择挂号日期");
        }

        Date date = DateUtil.parseDate(registeredDate, "yyyy-MM-dd");
        if (date == null) {
            return response.failedWithParameterError("预约日期格式不正确");
        }
        DatePeriodEnum datePeriodEnum = DatePeriodEnum.valueOf(period);
        if (datePeriodEnum == null) {
            return response.failed(BaseResponse.PARAMETER_ERROR, "预约时段不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(startTime)) {
            return response.failedWithParameterError("预约开始时间不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(endTime)) {
            return response.failedWithParameterError("预约结束时间不存在");
        }
        if (medicalCardId < 1) {
            return response.failedWithParameterError("请选择就诊人");
        }
        if (StringHelper.isNullOrWhiteSpace(scheduleItemCode)) {
            return response.failedWithParameterError("门诊排班项记录标识不能为空");
        }

        int userId = getUserId(userSrv.getCurrentOpenId(), hospitalId);
        if (userId == 0) {
            return response.failedWithParameterError("请先登录");
        }

        try {
            int total = registeredFee + medicalFee;
            int paymentChannel = total > 0
                    ? PaymentChannelEnum.WeChat.getValue()
                    : PaymentChannelEnum.FREE.getValue();
            int source;
            int terminal = WebAppContext.current().getTerminal();
            switch (TerminalEnum.valueOf(terminal)) {
                case TAI_HE_OFFICIAL:
                    source = TerminalEnum.TAI_HE_OFFICIAL.getValue();
                    break;
                case NFYYBYFY_WXAPP:
                    source = TerminalEnum.NFYYBYFY_WXAPP.getValue();
                    break;
                default:
                    source = TerminalEnum.TaiheWxOfficial.getValue();
                    break;
            }

            CreateRegisteredRequest req = CreateRegisteredRequest.newBuilder()
                    .setDeptCode(deptCode)
                    .setDeptName(deptName)
                    .setDoctorCode(doctorCode)
                    .setDoctorName(doctorName)
                    .setTotal(total)
                    .setRegisteredFee(registeredFee)
                    .setMedicalFee(medicalFee)
                    .setRegisteredDate(date.getTime())
                    .setStartTime(startTime)
                    .setEndTime(endTime)
                    .setUserId(userId)
                    .setMedicalCardId(medicalCardId)
                    .setScheduleItemCode(scheduleItemCode)
                    .setPaymentChannel(paymentChannel)
                    .setSource(source)
                    .setPeriod(period)
                    .setDoctorTitle("")
                    .setDeptId(Checker.getIntegerValue(deptId))
                    .setLockQueueNo(lockQueueNo)
                    .setAvailableNumStr(availableNumStr)
                    .setHospitalId(hospitalId)
                    .setSubHospitalId(subHospitalId)
                    .setDoctorSessTypeCode(doctorSessTypeCode)
                    .setDoctorSessTypeName(doctorSessTypeName)
                    .build();
            CreateRegisteredResponse res = taiheRegisterServiceBlockingStub.createRegistered(req);

            if (res.getCode() != ResultCode.SUCCEED_VALUE) {
                //预约失败
                return response.failedWithAppError(res.getMsg());
            }

            if (!systemSrv.checkIsNetDept(deptCode, hospitalId)) {
                //非互联网医院名医诊区挂号
                Map<String, Object> data = new HashMap<>();
                data.put("orderId", res.getOrderId());
                data.put("orderNo", res.getOrderNo());
                data.put("orderType", res.getOrderType());
                data.put("status", res.getStatus());
                return response.succeed(data);
            }

            //如果是南方医院太和分院（互联网医院名医诊区），则创建线下就诊订单
            int regId = res.getRegId();
            int doctorId = res.getDoctorId();
            String name = res.getName();
            String idNo = res.getIdNo();
            String mobile = res.getMobile();

            //创建线下就诊订单

            // 患者小程序使用原来接口的 sourceCode，见 {@link OfflineConsultController#create()}
            int offlineSource;
            switch (TerminalEnum.valueOf(WebAppContext.current().getTerminal())) {
                case TAI_HE_INTERNET_HOSPITAL_PATIENT_MINI_PROGRAM:
                    offlineSource = OfflineConsultationSourceEnum.SCENE_SCAN.getValue();
                    break;
                case NFYYBYFY_WXAPP:
                    offlineSource = OfflineConsultationSourceEnum.NFYYBYFY_WXAPP.getValue();
                    break;
                default:
                    offlineSource = OfflineConsultationSourceEnum.TAIHE_WX_OFFICIAL.getValue();
                    break;
            }
            CreateOfflineConsultationRequest createOfflineConsultationReq = CreateOfflineConsultationRequest.newBuilder()
                    .setHisClinicCode(0)
                    .setDoctorId(doctorId)
                    .setName(name)
                    .setIdNo(idNo)
                    .setMobile(mobile)
                    .setUserId(userId)
                    .setSource(offlineSource)
                    .setRegisteredDate(date.getTime())
                    .setRegId(regId)
                    .build();
            CreateOfflineConsultationResponse createOfflineConsultationRes =
                    offlineConsultingServiceBlockingStub.createOfflineConsultation(createOfflineConsultationReq);

            if (createOfflineConsultationRes.getCode() != ResultCode.SUCCEED_VALUE) {
                return response.failedWithAppError(createOfflineConsultationRes.getMsg());
            }

            Map<String, Object> data = new HashMap<>();
            data.put("orderId", createOfflineConsultationRes.getOrderId());
            data.put("orderNo", createOfflineConsultationRes.getOrderNo());
            data.put("orderType", createOfflineConsultationRes.getOrderType());

            // todo：20210527 为了提高预约挂号速度，弄一个列表用作缓冲，挂号成功，需要删除redis中的key
//            String openId = userService.getCurrentOpenId();
//            if (!Checker.isNone(openId)) {
//                String userKey = String.format(ConstantDef.YWT_COVID19_LIST_KEY, openId);
//                redisTemplate.delete(userKey);
//            }

            return response.succeed(data);
        } catch (Exception e) {
            logger.error("create({}): {}", reqBody, e.getMessage(), e);
            return response.error();
        }
    }

    /**
     * 取消预约
     * <p>
     * reqBody -> orderId 订单ID
     *
     * @param reqBody 入参
     * @return
     */
    @RequestMapping({"/cancel"})
    public BaseResponse cancel(@RequestBody Map<String, Object> reqBody) {
        BaseResponse response = new BaseResponse();
        Integer orderId = (Integer) reqBody.getOrDefault("orderId", 0);
        int hospitalId = Checker.getIntegerValue((Integer) reqBody.getOrDefault("hospitalId", 0));
        if (orderId < 1) {
            return response.failedWithParameterError("订单不存在");
        }
        if (hospitalId <= 0) {
            hospitalId = BizUtil.getHospitalIdByTerminalId(BizUtil.getCurrentTerminalWrapped());
        }
        int userId = getUserId(userSrv.getCurrentOpenId(), hospitalId);
        if (userId == 0) {
            return response.failedWithParameterError("请先登录");
        }

        try {
            CancelRegisteredRequest req = CancelRegisteredRequest.newBuilder()
                    .setOrderId(orderId)
                    .setUserId(userId)
                    .setHospitalId(hospitalId)
//                    .setUserId(userSrv.getCurrentUserId())
                    .build();
            CancelRegisteredResponse res = taiheRegisterServiceBlockingStub.cancelRegistered(req);
            if (res.getCode() == ResultCode.SUCCEED_VALUE) {
                Map<String, Object> data = new HashMap<>();
                data.put("status", res.getStatus());
                return response.succeed(data);
            }
            return response.failedWithAppError(res.getMsg());
        } catch (Exception e) {
            logger.error("cancel({}): {}", reqBody, e.getMessage(), e);
            return response.error();
        }
    }

    /**
     * 无诊疗卡预约挂号（境外人士使用）
     *
     * @param reqBody
     * @return
     */
    @RequestMapping("/foreigner/create")
    public BaseResponse registerWithoutMedicalCard(@RequestBody Map<String, Object> reqBody) {
        BaseResponse response = new BaseResponse();
        String deptCode = (String) reqBody.getOrDefault("deptCode", "");
        String deptName = (String) reqBody.getOrDefault("deptName", "");
        String doctorCode = (String) reqBody.getOrDefault("doctorCode", "");
        String doctorName = (String) reqBody.getOrDefault("doctorName", "");
        Integer registeredFee = (Integer) reqBody.getOrDefault("registeredFee", 0);
        Integer medicalFee = (Integer) reqBody.getOrDefault("medicalFee", 0);
        String registeredDate = (String) reqBody.getOrDefault("registeredDate", "");
        Integer period = (Integer) reqBody.getOrDefault("period", 0);
        String startTime = (String) reqBody.getOrDefault("startTime", "");
        String endTime = (String) reqBody.getOrDefault("endTime", "");
        String scheduleItemCode = (String) reqBody.getOrDefault("scheduleItemCode", "");
        Integer deptId = (Integer) reqBody.getOrDefault("deptId", 0);
        String idType = (String) reqBody.getOrDefault("idType", "");
        String idNo = (String) reqBody.getOrDefault("idNo", "");
        String patientName = (String) reqBody.getOrDefault("patientName", "");
        String patientMobile = (String) reqBody.getOrDefault("patientMobile", "");
        String patientBirthday = (String) reqBody.getOrDefault("patientBirthday", "");
        Integer sex = (Integer) reqBody.getOrDefault("sex", 0);
        int hospitalId = Checker.getIntegerValue((Integer) reqBody.getOrDefault("hospitalId", 0));
        if (hospitalId <= 0) {
            hospitalId = BizUtil.getHospitalIdByTerminalId(BizUtil.getCurrentTerminalWrapped());
        }
        if (StringHelper.isNullOrWhiteSpace(deptCode) || StringHelper.isNullOrWhiteSpace(deptName)) {
            return response.failedWithParameterError("科室不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(doctorCode) || StringHelper.isNullOrWhiteSpace(doctorName)) {
            return response.failedWithParameterError("医生不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(registeredDate)) {
            return response.failedWithParameterError("请选择挂号日期");
        }

        Date date = DateUtil.parseDate(registeredDate, "yyyy-MM-dd");
        if (date == null) {
            return response.failedWithParameterError("预约日期格式不正确");
        }
        DatePeriodEnum datePeriodEnum = DatePeriodEnum.valueOf(period);
        if (datePeriodEnum == null) {
            return response.failed(BaseResponse.PARAMETER_ERROR, "预约时段不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(startTime)) {
            return response.failedWithParameterError("预约开始时间不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(endTime)) {
            return response.failedWithParameterError("预约结束时间不存在");
        }
        if (StringHelper.isNullOrWhiteSpace(scheduleItemCode)) {
            return response.failedWithParameterError("门诊排班项记录标识不能为空");
        }
        if (StringHelper.isNullOrWhiteSpace(idType)) {
            return response.failedWithParameterError("请选择证件类型");
        }
        if (StringHelper.isNullOrWhiteSpace(idNo)) {
            return response.failedWithParameterError("请输入证件号码");
        }
        if (StringHelper.isNullOrWhiteSpace(patientName)) {
            return response.failedWithParameterError("姓名不能为空");
        }
        if (StringHelper.isNullOrWhiteSpace(patientMobile)) {
            return response.failedWithParameterError("手机号不能为空");
        }
        if (sex != SexEnum.Female.getValue() && sex != SexEnum.Male.getValue()) {
            return response.failedWithParameterError("请选择性别");
        }

        Date birthday = DateUtil.parseDate(patientBirthday, "yyyy-MM-dd");
        if (birthday == null) {
            return response.failedWithParameterError("出生日期格式不正确");
        }
        int userId = getUserId(userSrv.getCurrentOpenId(), hospitalId);
        if (userId == 0) {
            return response.failedWithParameterError("请先登录");
        }
        try {
            int total = registeredFee + medicalFee;
            RegisterWithoutMedicalCardRequest req = RegisterWithoutMedicalCardRequest.newBuilder()
                    .setDeptId(Checker.getIntegerValue(deptId))
                    .setDeptCode(deptCode)
                    .setDeptName(deptName)
                    .setDoctorCode(doctorCode)
                    .setDoctorName(doctorName)
                    .setTotal(total)
                    .setRegisteredFee(registeredFee)
                    .setMedicalFee(medicalFee)
                    .setRegisteredDate(date.getTime())
                    .setPeriod(period)
                    .setStartTime(startTime)
                    .setEndTime(endTime)
                    .setUserId(userId)
                    .setScheduleItemCode(scheduleItemCode)
                    .setIdType(idType)
                    .setIdNo(idNo)
                    .setPatientName(patientName)
                    .setPatientMobile(patientMobile)
                    .setPatientSex(sex)
                    .setBirthday(birthday.getTime())
                    .setHospitalId(hospitalId)
                    .build();
            RegisterWithoutMedicalCardResponse res = taiheRegisterServiceBlockingStub.registerWithoutMedicalCard(req);
            return res.getCode() == ResultCode.SUCCEED_VALUE ? response.succeed() : response.failedWithAppError(res.getMsg());
        } catch (Exception e) {
            logger.error("registerWithoutMedicalCard({}): {}", reqBody, e.getMessage(), e);
            return response.error();
        }
    }

    private int getUserId(String openId, int hospitalId) {
        try {
            logger.info("TaiheRegisterController#getUserId(openId={} ): union_id {} terminal {} userId {}", openId,
                    userSrv.getCurrentUnionId(), userSrv.getCurrentTerminal(), userSrv.getCurrentUserId());
//            int userId = userSrv.getCurrentUserId();
            int userId = userSrv.getCurrentUserIdWrapped();
            if (userId > 0) {
                return userId;
            }

            //网关 AuthData 取不到 userId，则根据 openId 从数据库读取
            GetOfficialUserInfoRequest req = GetOfficialUserInfoRequest.newBuilder()
                    .setUnionId("")
                    .setOpenId(openId)
                    .setTerminal(userSrv.getCurrentTerminal())
                    .setHospitalId(hospitalId)
                    .build();
            GetOfficialUserInfoResponse res = userServiceBlockingStub.getOfficialUserInfo(req);
            Result result = res.getResult();

            if (result.getCode() == ResultCode.SUCCEED) {
                return res.getUserId();
            }
        } catch (Exception e) {
            logger.error("getUserInfoByOpenIdRequest({}): {}", openId, e.getMessage(), e);
        }
        return 0;
    }

    @RequestMapping(value = {"/additionalFee"}, method = RequestMethod.POST)
    public BaseResponse calAdditionalFee(@RequestBody CalAdditionalFeeReq reqData) {
        BaseResponse baseResponse = new BaseResponse();
        try {
            int medicalCardId = Checker.getIntegerValue(reqData.getMedicalCardId());
            CheckUtil.ensureLargerThanZero(medicalCardId, "诊疗卡 id 有误");
            int medicalFee = Checker.getIntegerValue(reqData.getMedicalFee());
            int registeredFee = Checker.getIntegerValue(reqData.getRegisteredFee());
            int hospitalId = Checker.getIntegerValue(reqData.getHospitalId());
            int period = Checker.getIntegerValue(reqData.getPeriod());
            String doctorSessTypeCode = Checker.getStringValue(reqData.getDoctorSessTypeCode());
            String doctorSessTypeName = Checker.getStringValue(reqData.getDoctorSessTypeName());
            if (hospitalId <= 0) {
                hospitalId = BizUtil.getHospitalIdByTerminalId(BizUtil.getCurrentTerminalWrapped());
            }
            int userId = getUserId(userSrv.getCurrentOpenId(), hospitalId);
            CheckUtil.ensureLargerThanZero(userId, "userId 有误");
            CalAdditionalFeeRequest request = CalAdditionalFeeRequest.newBuilder()
                    .setMedicalCardId(medicalCardId)
                    .setMedicalFee(medicalFee)
                    .setRegisteredFee(registeredFee)
                    .setUserId(userId)
                    .setHospitalId(hospitalId)
                    .setPeriod(period)
                    .setDoctorSessTypeCode(doctorSessTypeCode)
                    .setDoctorSessTypeName(doctorSessTypeName)
                    .build();
            CalAdditionalFeeResponse response = taiheRegisterServiceBlockingStub.calAdditionalFee(request);
            if (response.getCode() == BaseResponse.SUCCEED) {
                CalAdditionalFeeResp resp = new CalAdditionalFeeResp();
                resp.setPayMedicalFee(String.format("%.2f", response.getPayMedicalFee() / 100d));
                resp.setPayTotal(response.getPayTotal());
                resp.setIsFreeMedicalTreat(response.getIsFreeMedicalTreat());
                return baseResponse.succeed(resp);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (Exception e) {
            logger.error("TaiheRegisterController#additionalFee(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }
}
