package com.ywt.alipaympapi.service.impl;

import com.alibaba.fastjson.JSON;
import com.ywt.alipaympapi.core.utils.*;
import com.ywt.alipaympapi.models.BaseResponse;
import com.ywt.alipaympapi.models.enums.RelationshipEnum;
import com.ywt.alipaympapi.models.enums.SexEnum;
import com.ywt.alipaympapi.models.enums.SmsCodeTypeEnum;
import com.ywt.alipaympapi.service.AuthService;
import com.ywt.alipaympapi.service.IsvMedicCardService;
import com.ywt.alipaympapi.service.services.MessageSrv;
import com.ywt.core.exception.AppMessageException;
import com.ywt.gapi.Result;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.ResultInt;
import com.ywt.gapi.taihe.register.CreateMedicalCardRequest;
import com.ywt.gapi.taihe.register.CreateMedicalCardResponse;
import com.ywt.gapi.taihe.register.TaiheRegisterServiceGrpc;
import com.ywt.gapi.user.*;
import com.ywt.model.PageVO;
import com.ywt.model.Pagination;
import com.ywt.request.card.UpdatePatientRequest;
import com.ywt.request.card.*;
import com.ywt.response.card.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IsvMedicCardServiceImpl implements IsvMedicCardService {
    @Autowired
    private TaiheRegisterServiceGrpc.TaiheRegisterServiceBlockingStub taiheRegisterServiceBlockingStub;
    @Autowired
    private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
    @Autowired
    private MessageSrv messageSrv;

    public static final int CARD_TYPE_NORMAL = 0; // 普通卡
    public static final int CARD_TYPE_MED_INSU = 1; // 医保卡
    public static final String CARD_TYPE_STR_NORMAL = "0"; // 普通卡
    public static final String CARD_TYPE_STR_MED_INSU = "1"; // 医保卡

    @Override
    public CreateOrBindCardResponseData createOrBindMedicCard(CreateOrBindCardRequest request) throws Exception {
        //用户唯一id
        // String userId = request.getUserId();
        //标志新建or绑定操作; 0=新建 1=绑定
        Integer type = request.getType();
        //就诊卡卡号，仅绑定操作时有效
        String cardNum = request.getCardNum();
        //性别; 男|女
        String sex = request.getSex();
        //生日（yyyy-MM-dd）
        String birthDay = request.getBirthDay();
        //验证码
        String authCode = request.getAuthCode();
        //关系
        String relationShip = request.getRelationShip();
        //是否默认（1-是，2-否）
        String defaultCard = request.getDefaultCard();
        //手机号
        String phoneNo = request.getPhoneNumber();
        //身份证号码
        String idNo = request.getIdCardNo();
        //姓名
        String patientName = Checker.getStringValue(request.getName());
        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        CreateOrBindCardResponseData resp = new CreateOrBindCardResponseData();
        // type: 标志新建or绑定操作; 0=新建 1=绑定
        if (type == 0) {
            String city = "广州市";
            String address = "默认详情地址";
            String isInsu = "";
            if (!IdCardUtil.verify(idNo)) {
                throw new AppMessageException(String.format("身份证不合法：%s", idNo));
            }
            CheckUtil.ensureValidPhoneNumber(phoneNo, String.format("手机号不合法：%s", phoneNo));
            CheckUtil.ensureNotEmpty(patientName, "请完善姓名");
            CreateMedicalCardResponse response = taiheRegisterServiceBlockingStub.createMedicalCard(CreateMedicalCardRequest.newBuilder()
                    .setPhoneNo(phoneNo)
                    .setIdNo(idNo)
                    .setPatientName(patientName)
                    .setCity(city)
                    .setAddress(address)
                    .setIsInsu(isInsu)
                    .setHospitalId(hospitalId)
                    .setUserId(userId)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                resp.setUserId(request.getUserId());
                resp.setCardNum(response.getMedicalCardNo());
                resp.setName(patientName);
                resp.setSex(sex);
                resp.setBirthDay(birthDay);
                resp.setIdCardNo(idNo);
                resp.setPhoneNumber(phoneNo);
                resp.setBalance("0.00");
            } else {
                throw new AppMessageException(response.getInfo());
            }
            return resp;
        }
        // type: 标志新建or绑定操作; 0=新建 1=绑定
        if (type == 1) {
            if (hospitalId < 1) {
                throw new AppMessageException("请选择医院");
            }
            if (StringHelper.isNullOrWhiteSpace(cardNum)) {
                throw new AppMessageException("请填写就诊卡号");
            }
            if (StringHelper.isNullOrWhiteSpace(patientName)) {
                throw new AppMessageException("请填写真实的姓名");
            }
            if (StringHelper.isNullOrWhiteSpace(phoneNo)) {
                throw new AppMessageException("请填写在医院预留的手机号");
            }
            if (StringHelper.isNullOrWhiteSpace(authCode)) {
                throw new AppMessageException("请输入验证码");
            }
            BaseResponse response = messageSrv.checkSmsCode(phoneNo, authCode, SmsCodeTypeEnum.Medical_Card_Bind.getValue());
            if (response.getCode() != BaseResponse.SUCCEED) {
                throw new AppMessageException(response.getInfo());
            }
            // 通过枚举类的方法，将文字转换成数字
            int relationshipInt = RelationshipEnum.valueOf(relationShip).getValue();
            // defaultCardInt: 1-是，0-否
            int defaultCardInt = "1".equals(defaultCard) ? 1 : 0;
            AddMedicalCardRequest addMedicalCardRequest = AddMedicalCardRequest.newBuilder()
                    .setUserId(userId)
                    .setHospitalId(hospitalId)
                    .setCardNo(cardNum)
                    .setRealName(patientName)
                    .setMobile(phoneNo)
                    .setRelationship(relationshipInt)
                    .setDefaultCard(defaultCardInt)
                    .build();
            ResultInt resultInt = userServiceBlockingStub.addMedicalCard(addMedicalCardRequest);
            if (resultInt.getCode() == ResultCode.SUCCEED) {
                int cent = Checker.parseInt(resultInt.getInfo());
                double balance = cent / 100d;
                resp.setUserId(request.getUserId());
                resp.setCardNum(request.getCardNum());
                resp.setName(patientName);
                resp.setSex(sex);
                resp.setBirthDay(birthDay);
                resp.setIdCardNo(idNo);
                resp.setPhoneNumber(phoneNo);
                resp.setBalance(String.format("%.2f", balance));
            } else {
                throw new AppMessageException(response.getInfo());
            }
        }
        return resp;
    }

    @Override
    public UpdateCardResponseData updateMedicCard(UpdateCardRequest request) throws Exception {
        throw new AppMessageException("暂不支持修改诊疗卡功能");
    }

    // 就诊卡详情
    @Override
    public QuerySingleCardResponseData querySingleMedicCard(QuerySingleCardRequest request) throws Exception {
        // 此处传诊疗卡ID和userId
        String cardNum = request.getCardNum();
        CheckUtil.ensureNotEmpty(cardNum, "诊疗卡号不能为空");
        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        List<MedicalCard> list = getUserMedCardList(userId, hospitalId).stream()
                .filter(c -> Checker.getStringValue(c.getCardNo()).equals(cardNum))
                .collect(Collectors.toList());
        if (list.isEmpty()) return null;
        MedicalCard medicalCard = list.get(0);
        double balance = medicalCard.getBalance() / 100d;
        QuerySingleCardResponseData item = new QuerySingleCardResponseData();
        item.setCardNum(medicalCard.getCardNo());//就诊卡卡号/医保卡卡号
        item.setType(CARD_TYPE_STR_NORMAL);// 标记查询卡类型
        item.setName(medicalCard.getPatientName());//姓名
        item.setSex(SexEnum.getSexDisplayName(medicalCard.getSex()));//性别
        item.setBirthDay(medicalCard.getBirthday());//生日
        item.setIdCardNo(medicalCard.getIdNo());//身份证号码
        item.setPhoneNumber(medicalCard.getMobile());//手机号
        item.setBalance(balance + "");//卡内余额
        item.setRelationShip(RelationshipEnum.valueOf(medicalCard.getRelationship()).getDisplayName()); // 关系
        item.setDefaultCard(medicalCard.getIsDefault() ? "是" : "否");// FIXME: 是否是默认就诊卡
        item.setId(medicalCard.getCardId());
        return item;
    }

    // 我的证件
    @Override
    public QueryDefaultCardResponseData queryDefaultMedicCard(QueryDefaultCardRequest request) throws Exception {
        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        List<MedicalCard> list = getUserMedCardList(userId, hospitalId).stream()
                .sorted(Comparator.comparing(MedicalCard::getLastChosenTime).reversed())
                .collect(Collectors.toList());
        if (list.isEmpty()) return null;
        MedicalCard medicalCard = list.get(0);
        double balance = medicalCard.getBalance() / 100d;
        QueryDefaultCardResponseData item = new QueryDefaultCardResponseData();
        item.setCardNum(medicalCard.getCardNo());//就诊卡卡号/医保卡卡号
        item.setType(CARD_TYPE_STR_NORMAL);// 标记查询卡类型，默认普通卡
        item.setName(medicalCard.getPatientName());//姓名
        item.setSex(SexEnum.getSexDisplayName(medicalCard.getSex()));//性别
        item.setBirthDay(medicalCard.getBirthday());//生日
        item.setIdCardNo(medicalCard.getIdNo());//身份证号码
        item.setPhoneNumber(medicalCard.getMobile());//手机号
        item.setBalance(balance + "");//卡内余额
        item.setRelationShip(RelationshipEnum.valueOf(medicalCard.getRelationship()).getDisplayName()); // 关系
        item.setDefaultCard(medicalCard.getIsDefault() ? "是" : "否");//是否是默认就诊卡
        item.setPatientId("");//如果是医保卡，传参保城市
        item.setId(medicalCard.getCardId());
        return item;
    }

    // 查询就诊卡列表
    @Override
    public PageVO<QueryListCardResponseData> queryListMedicCard(QueryListCardRequest request) throws Exception {
        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        int total;
        List<QueryListCardResponseData> lst = new LinkedList<>();
        List<MedicalCard> medicalCards = getUserMedCardList(userId, hospitalId);
        total = medicalCards.size();
        for (MedicalCard medicalCard : medicalCards) {
            double balance = medicalCard.getBalance() / 100d;
            QueryListCardResponseData item = new QueryListCardResponseData();
            item.setCardNum(medicalCard.getCardNo());//就诊卡卡号/医保卡卡号
            item.setType(CARD_TYPE_NORMAL);//标记查询卡类型
            item.setName(medicalCard.getPatientName());//姓名
            item.setSex(SexEnum.getSexDisplayName(medicalCard.getSex()));//性别
            item.setBirthDay(medicalCard.getBirthday());//生日
            item.setIdCardNo(medicalCard.getIdNo());//身份证号码
            item.setPhoneNumber(medicalCard.getMobile());//手机号
            item.setBalance(balance + "");//卡内余额
            item.setIsDefault(medicalCard.getIsDefault());//是否是默认就诊卡
            item.setCity("");//如果是医保卡，传参保城市
            item.setCardOrgName("");//如果是医保卡，传发卡机构
            lst.add(item);
        }
        Pagination pagination = new Pagination(1, 1, total);
        return new PageVO<>(pagination, lst);
    }

    // 删除就诊卡
    @Override
    public DeleteCardResponseData deleteMedicCard(DeleteCardRequest request) throws Exception {
        int cardId = Checker.parseInt(request.getCardId());
        CheckUtil.ensureLargerThanZero(cardId, "诊疗卡 id 不正确");
        int userId = ContextHelper.getCurrentUserIdWrapped();
        DeleteCardResponseData responseData = new DeleteCardResponseData();
        DeleteMedicalCardRequest deleteMedicalCardRequest = DeleteMedicalCardRequest.newBuilder()
                .setCardId(cardId)
                .setUserId(userId)
                .build();
        Result result = userServiceBlockingStub.deleteMedicalCard(deleteMedicalCardRequest);
        responseData.setIsSuccess(result.getCode() == ResultCode.SUCCEED);
        responseData.setInfo(result.getInfo());
        return responseData;
    }

    @Override
    public BindMedInsuranceCardResponseData bindMedInsuranceCard(BindMedInsuranceCardRequest request) throws Exception {
        BindMedInsuranceCardResponseData resp = new BindMedInsuranceCardResponseData();
        String patientName = request.getName();//姓名
        String sex = request.getSex();//性别
        String birthDay = request.getBirthDay();//生日
        String idCardNo = request.getIdCardNo();//身份证号码
        String phoneNo = request.getPhoneNumber();//手机号
        String cardNum = request.getMedInsuranceNum();//医保卡识别号

        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        if (hospitalId < 1) {
            throw new AppMessageException("请选择医院");
        }
        if (StringHelper.isNullOrWhiteSpace(cardNum)) {
            throw new AppMessageException("请填写就诊卡号");
        }
        if (StringHelper.isNullOrWhiteSpace(patientName)) {
            throw new AppMessageException("请填写真实的姓名");
        }
        if (StringHelper.isNullOrWhiteSpace(phoneNo)) {
            throw new AppMessageException("请填写在医院预留的手机号");
        }

        // 通过枚举类的方法，将文字转换成数字
        int relationshipInt = 0;
        // defaultCardInt: 1-是，0-否
        int defaultCardInt = 0;
        AddMedicalCardRequest addMedicalCardRequest = AddMedicalCardRequest.newBuilder()
                .setUserId(userId)
                .setHospitalId(hospitalId)
                .setCardNo(cardNum)
                .setRealName(patientName)
                .setMobile(phoneNo)
                .setRelationship(relationshipInt)
                .setDefaultCard(defaultCardInt)
                .build();
        ResultInt resultInt = userServiceBlockingStub.addMedicalCard(addMedicalCardRequest);
        if (resultInt.getCode() == ResultCode.SUCCEED) {
            resp.setUserId(request.getUserId());
            resp.setCardNum(request.getMedInsuranceNum());
            resp.setName(patientName);
            resp.setSex(sex);
            resp.setBirthDay(birthDay);
            resp.setIdCardNo(idCardNo);
            resp.setPhoneNumber(phoneNo);
        } else {
            throw new AppMessageException(resultInt.getInfo());
        }
        return resp;
    }

    // 就诊人列表
    @Override
    public List<QueryPatientListResponse> queryPatientList(QueryPatientListRequest request) throws Exception {
        int hospitalId = BizUtil.getCurrentHospitalId();
        int userId = ContextHelper.getCurrentUserIdWrapped();
        return getUserMedCardList(userId, hospitalId).stream()
                .map(c -> {
                    QueryPatientListResponse r = new QueryPatientListResponse();
                    List<MedicCard> medicCards = new ArrayList<>();
                    r.setId(String.valueOf(c.getCardId()));
                    r.setName(c.getPatientName());
                    r.setAge(getAgeFromMedicalCard(c));
                    r.setSex(SexEnum.getSexDisplayName(c.getSex()));
                    r.setPhoneNumber(BizUtil.masked(c.getMobile()));
                    r.setBirthDay(c.getBirthday());
                    r.setIdCardNo(BizUtil.masked(c.getIdNo()));
                    r.setRelationShip(RelationshipEnum.valueOf(c.getRelationship()).getDisplayName());
                    r.setDefaultPatient(false); // TODO: 怎么确定默认就诊人
                    r.setBindCardNum(c.getCardNo());
                    MedicCard card = new MedicCard();
                    card.setCardNum(c.getCardNo());
                    card.setType(CARD_TYPE_NORMAL);
                    card.setBalance(String.valueOf(c.getBalance() / 100d));
                    medicCards.add(card);
                    r.setMedicCards(medicCards);
                    return r;
                })
                .collect(Collectors.toList());
    }

    private String getAgeFromMedicalCard(MedicalCard card) {
        int age = -1;
        String idNo = card.getIdNo();
        String birthday = card.getBirthday();
        if (!StringHelper.isNullOrEmpty(idNo)) {
            try {
                age = IdCardUtil.getCurrentAge(idNo);
            } catch (Exception e) {
                log.error("IsvMedicCardServiceImpl#getAgeFromMedicalCard(idNo = {}): 无法获取年龄 {}", idNo, e.getMessage(), e);
            }
        } else if (!StringHelper.isNullOrEmpty(birthday)) {
            try {
                age = IdCardUtil.getCurrentAgeByBirthday(birthday, IdCardUtil.DATE_PATTERN2);
            } catch (Exception e) {
                log.error("IsvMedicCardServiceImpl#getAgeFromMedicalCard(birthday = {}): 无法获取年龄 {}", birthday, e.getMessage(), e);
            }
        }
        // 不返回年龄为 "-1"
        if (age < 0) {
            return "";
        }
        return String.valueOf(age);
    }

    @Override
    public PatientBindCardResponse bindMedicCard(PatientBindCardRequest request) throws Exception {

        return null;
    }

    // 删除就诊人
    @Override
    public DeletePatientResponse deletePatient(DeletePatientRequest request) throws Exception {
        int cardId = Checker.parseInt(request.getId()); // 诊疗卡 id
        CheckUtil.ensureLargerThanZero(cardId, "诊疗卡 id 不正确");
        int userId = ContextHelper.getCurrentUserIdWrapped();
        DeletePatientResponse responseData = new DeletePatientResponse();
        DeleteMedicalCardRequest deleteMedicalCardRequest = DeleteMedicalCardRequest.newBuilder()
                .setCardId(cardId)
                .setUserId(userId)
                .build();
        Result result = userServiceBlockingStub.deleteMedicalCard(deleteMedicalCardRequest);
        responseData.setIsSuccess(result.getCode() == ResultCode.SUCCEED);
        responseData.setInfo(result.getInfo());
        return responseData;
    }

    @Override
    public AddPatientResponse addPatient(AddPatientRequest request) throws Exception {
        return null;
    }

    @Override
    public UpdatePatientResponse updatePatient(UpdatePatientRequest request) throws Exception {
        return null;
    }

    /**
     * 根据 userId & hospitalId 获取用户可用就诊卡列表
     */
    public List<MedicalCard> getUserMedCardList(int userId, int hospitalId) throws AppMessageException {
        GetMedicalCardListRequest getMedicalCardListRequest = GetMedicalCardListRequest.newBuilder()
                .setHospitalId(hospitalId)
                .setUserId(userId)
                .build();
        GetMedicalCardListResponse getMedicalCardListResponse = userServiceBlockingStub.getMedicalCardList(getMedicalCardListRequest);
        Result result = getMedicalCardListResponse.getResult();
        if (result.getCode() != ResultCode.SUCCEED) throw new AppMessageException(result.getInfo());
        return getMedicalCardListResponse.getMedicalCardsList();
    }

    // 查看就诊人详情
    @Override
    public QueryPatientDetailResponse querySinglePatient(QueryPatientDetailRequest request) throws Exception {
        String id = request.getId(); // 对应 medicalCard 的 id
        int userId = ContextHelper.getCurrentUserIdWrapped();
        int hospitalId = BizUtil.getCurrentHospitalId();
        MedicalCard c = getUserMedCardList(userId, hospitalId).stream()
                .filter(i -> i.getCardId() == Checker.parseInt(id))
                .findFirst()
                .orElse(null);
        if (c == null) throw new AppMessageException("找不到诊疗卡信息");
        QueryPatientDetailResponse r = new QueryPatientDetailResponse();
        List<MedicCard> medicCards = new ArrayList<>();
        r.setId(String.valueOf(c.getCardId()));
        r.setName(c.getPatientName());
        r.setAge(getAgeFromMedicalCard(c));
        r.setSex(SexEnum.getSexDisplayName(c.getSex()));
        r.setPhoneNumber(BizUtil.masked(c.getMobile()));
        r.setBirthDay(c.getBirthday());
        r.setIdCardNo(BizUtil.masked(c.getIdNo()));
        r.setRelationShip(RelationshipEnum.valueOf(c.getRelationship()).getDisplayName());
        r.setBindCardNum(c.getCardNo());
        MedicCard card = new MedicCard();
        card.setCardNum(c.getCardNo());
        card.setType(CARD_TYPE_NORMAL);
        card.setBalance(String.valueOf(c.getBalance() / 100d));
        medicCards.add(card);
        r.setMedicCards(medicCards);
        return r;
    }

    @Override
    public List<MyCardListResponse> myCardList(MyCardListRequest request) throws Exception {
        return null;
    }
}
