package com.ywt.alipaympapi.service.impl;

import com.alipay.api.domain.AlipayTradeCreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.ywt.alipaympapi.core.utils.*;
import com.ywt.alipaympapi.face.IPayFace;
import com.ywt.alipaympapi.models.Constants;
import com.ywt.core.exception.AppMessageException;
import com.ywt.gapi.Result;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.drug.GetOneKeyRegListRequest;
import com.ywt.gapi.drug.GetOneKeyRegListResponse;
import com.ywt.gapi.order.GetOutpatientOrderListRequest;
import com.ywt.gapi.order.GetOutpatientOrderListResponse;
import com.ywt.gapi.order.OrderServiceGrpc;
import com.ywt.gapi.order.OutpatientOrder;
import com.ywt.gapi.taihe.outpaitent.*;
import com.ywt.gapi.taihe.outpaitent.BaseResult;
import com.ywt.gapi.third.taihe.*;
import com.ywt.gapi.third.taihe.GetOutpatientListRequest;
import com.ywt.gapi.third.taihe.GetOutpatientListResponse;
import com.ywt.model.PageVO;
import com.ywt.model.Pagination;
import com.ywt.request.pay.*;
import com.ywt.response.pay.*;
import com.ywt.alipaympapi.service.IsvPayService;
import com.ywt.response.report.QueryReportListResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IsvPayServiceImpl implements IsvPayService {
    @Resource
    private IPayFace payFace;

    public static final int TYPE_UNPAID_WX = 1;
    private static final int TYPE_PAID_WX = 2;

    public static final int TYPE_UNPAID_ZFB = 0;
    private static final int TYPE_PAID_ZFB = 1;



    @Autowired
    private TaiheServiceGrpc.TaiheServiceBlockingStub taiheServiceBlockingStub;

    @Autowired
    private TaiheOutpatientServiceGrpc.TaiheOutpatientServiceBlockingStub taiheOutpatientServiceBlockingStub;

    @Autowired
    private com.ywt.gapi.drug.DrugServiceGrpc.DrugServiceBlockingStub drugServiceBlockingStub;

    @Autowired
    private OrderServiceGrpc.OrderServiceBlockingStub orderServiceBlockingStub;

    @Override
    public TradeNoResponseData queryTradeNo(OutTradeNoRequest request) {
        return null;
    }

    @Override
    public TradeResultResponseData informTradeResult(TradeResultRequest request) {
        TradeResultResponseData data = new TradeResultResponseData();

        AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
        alipayTradeQueryModel.setTradeNo(request.getTradeNo());
        AlipayTradeQueryResponse response = payFace.tradeQuery(request.getAppId(), alipayTradeQueryModel);
        if ("TRADE_SUCCESS".equals(response.getTradeStatus())) {
            data.setStatus("TRADE_SUCCESS");
        }

        return data;
    }

    @Override
    public PayDetailResponseData queryPayDetail(PayDetailRequest request) throws Exception {
        int userId = ContextHelper.getCurrentUserIdWrapped();
        int hospitalId = BizUtil.getCurrentHospitalId();
        if(Checker.isNone(request.getStatus())){
            throw new RuntimeException("订单状态不能为空");
        }
        if(request.getStatus() == TYPE_UNPAID_ZFB){
            PayDetailResponseData da = new PayDetailResponseData();
            da.setDepName(Checker.getStringValue(request.getDepName()));
            da.setAge(request.getAge().toString());
            da.setSex(request.getSex());
            da.setStatus(request.getStatus());
            return da;
        }
        if (Checker.isNone(request.getInvoiceNo()) && Checker.isNone(request.getOutTradeNo())) {
            throw new RuntimeException("订单发票号不存在");
        }
        List<OrderItem> list = new LinkedList<>();
        PayDetailResponseData da = new PayDetailResponseData();
        String hisPatientId = Checker.getStringValue(request.getHisPatientId());
        switch (hospitalId) {
            default:
            case Constants.HOSPITAL_ID_NFYYBYFY:
                // 白云从 HIS 接口获取门诊缴费详情
                String invoiceNo = Checker.getStringValue(request.getInvoiceNo());
                CheckUtil.ensureNotEmpty(invoiceNo, "发票号不能为空");
                CheckUtil.ensureNotEmpty(hisPatientId, "HIS 病人 id 不能为空");
                // 根据 his_patient_id 获取诊疗卡信息
                String pName = "";
                Integer pAge = 0;
                String pGender = "";
                String cardNum = "";
                GetMedicalCardInfoByPatientIdRequest gResp = GetMedicalCardInfoByPatientIdRequest.newBuilder()
                        .setHisPatientId(hisPatientId)
                        .setHospitalId(hospitalId)
                        .setUserId(userId)
                        .build();
                GetMedicalCardInfoByPatientIdResponse gmcResp = taiheOutpatientServiceBlockingStub.getMedicalCardInfoByPatientId(gResp);
                if (gmcResp.getCode() == ResultCode.SUCCEED_VALUE) {
                    pName = gmcResp.getPatientName();
                    pAge = getPatientAgeSafely(gmcResp.getIdNo(), gmcResp.getBirthday());
                    pGender = IdCardUtil.getSex(gmcResp.getIdNo());
                    cardNum = Checker.getStringValue(gmcResp.getCardNo());

                }
                GetPaymentDetailResponse response2 = taiheServiceBlockingStub.getPaymentDetail(GetPaymentDetailRequest.newBuilder()
                        .setHospitalId(hospitalId)
                        .setInvoiceNo(invoiceNo)
                        .setHisPatientId(hisPatientId)
                        .setType("2")
                        .build());
                if (response2.getCode() != ResultCode.SUCCEED_VALUE)
                    throw new RuntimeException(response2.getMsg());
                if (!Checker.isNone(response2.getDetailList())) {
                    list = response2.getDetailList().stream()
                            .map(i -> {
                                OrderItem it = new OrderItem();
                                it.setItemName(i.getItemName());
                                it.setAmount(String.format("%.2f", i.getItemPrice() / 100d));
                                it.setItemNum(String.valueOf(i.getItemNumber()));
                                return it;
                            })
                            .collect(Collectors.toList());
                }
                da.setAge(pAge.toString());
                da.setUserName(pName);
                da.setSex(pGender);
                da.setPayDate(request.getDate());
                da.setOrderItems(list);
                da.setCardNum(cardNum);
                da.setOrderId("");
                da.setStatus(request.getStatus());
                break;

        }
        return da;
    }

    @Override
    public PageVO<PayHistoryResponseData> queryPayHistory(PayHistoryRequest request) throws Exception {
        List<PayHistoryResponseData> list = new ArrayList<>();
        int pageIndex = request.getPageIndex();
        int pageSize = request.getPageSize();
        int total = 0;
        if (Checker.isNone(request.getStatus())) {
            throw new RuntimeException("订单状态不能为空");
        }
        int status = Integer.parseInt(Checker.getStringValue(request.getStatus()));
        if (Checker.isNone(request.getHisPatientId())) {
            throw new RuntimeException("hisPatientI不能为空");
        }
        String hisPatientId = Checker.getStringValue(request.getHisPatientId());
        int userId = ContextHelper.getCurrentUserIdWrapped();
        String pName = "";
        int pAge = 0;
        String pGender = "";
        int hospitalId = BizUtil.getCurrentHospitalId();
        GetMedicalCardInfoByPatientIdRequest gResp = GetMedicalCardInfoByPatientIdRequest.newBuilder()
                .setHisPatientId(hisPatientId)
                .setHospitalId(hospitalId)
                .setUserId(userId)
                .build();
        GetMedicalCardInfoByPatientIdResponse resp = taiheOutpatientServiceBlockingStub.getMedicalCardInfoByPatientId(gResp);
        if (resp.getCode() == ResultCode.SUCCEED_VALUE) {
            pName = resp.getPatientName();
            pAge = getPatientAgeSafely(resp.getIdNo(), resp.getBirthday());
            pGender = IdCardUtil.getSex(resp.getIdNo());
        }
        switch (status) {
            case TYPE_UNPAID_ZFB:
                // 待缴费列表从 HIS 获取数据
                GetOutpatientListRequest req = GetOutpatientListRequest.newBuilder()
                        .setPatientId(hisPatientId)
                        .setType(TYPE_UNPAID_WX)
                        .setHospitalId(hospitalId)
                        .build();
                GetOutpatientListResponse result = taiheServiceBlockingStub.getOutpatientList(req);

                if (result.getCode() != ResultCode.SUCCEED_VALUE) {
                    throw new RuntimeException(result.getMsg());
                }
                List<Map<String, Object>> lst = new LinkedList<>();
                Map<String, Object> map;

                List<PaymentItem> paymentItems = result.getPaymentList();
                if (!Checker.isNone(paymentItems)) {
                    // 过滤处方门诊缴费单
                    GetOneKeyRegListRequest getOneKeyRegListRequest = GetOneKeyRegListRequest.newBuilder()
                            .setUserId(userId)
                            .build();
                    GetOneKeyRegListResponse getOneKeyRegListResponse = drugServiceBlockingStub.getOneKeyRegList(getOneKeyRegListRequest);
                    List<String> clinicCodes = getOneKeyRegListResponse.getCode() == ResultCode.SUCCEED_VALUE ? getOneKeyRegListResponse.getClinicCodeList() : new LinkedList<>();
                    List<PaymentItem> payItems = paymentItems;
                    if (!clinicCodes.isEmpty()) {
                        payItems = paymentItems.stream()
                                .filter(paymentItem -> !clinicCodes.contains(paymentItem.getClinicCode()))
                                .collect(Collectors.toList());
                    }
                    total = payItems.size();
                    for (PaymentItem payItem : payItems) {
                        PayHistoryResponseData data = new PayHistoryResponseData();
                        data.setStatus(status);
                        data.setTitle("");
                        data.setDepName(payItem.getDeptName());
                        data.setPrescribeDate(payItem.getPrescriptionDate());
                        data.setName(resp.getPatientName());
                        data.setAmount(String.format("%.2f", payItem.getTotalFee() / 100d));
                        data.setTradeNo(""); //Todo
                        data.setOutTradeNo("");//Todo
                        data.setIdNum("");//Todo
                        data.setInvoiceNo(Checker.getStringValue(payItem.getInvoiceNo()));
                        data.setHisPatientId(hisPatientId);
                        data.setAge(pAge);
                        data.setSex(pGender);
                        list.add(data);
//                        map.put("hisClinicCode", payItem.getClinicCode());
//                        map.put("hisOrderNo", payItem.getHisOrdNum());
//                        map.put("patientName", pName);
//                        map.put("orderInsType", payItem.getOrderInsType());
//                        map.put("patientAge", pAge);
//                        map.put("patientSex", pGender);
//                        map.put("doctorCode", payItem.getDoctorCode());
                        List<PayDetailItem> detailItems = payItem.getItemListList();
                        List<Map<String, Object>> items = new LinkedList<>();
                        for (PayDetailItem detailItem : detailItems) {
                            Map<String, Object> d = new HashMap<>();
                            d.put("name", detailItem.getItemName());
                            d.put("price", detailItem.getItemPrice());
                            d.put("code", detailItem.getItemCode());
                            d.put("number", detailItem.getItemNumber());
                            d.put("spec", detailItem.getItemSpec());
                            d.put("unit", detailItem.getItemUnit());
                            d.put("totalFee", detailItem.getItemTotalFee());
                            items.add(d);
                        }
//                        map.put("detailItems", items);
//                        lst.add(map);
                        // 保存门诊缴费明细到数据库
                        SaveOutpatientOrderDetailsRequest sReq = SaveOutpatientOrderDetailsRequest.newBuilder()
                                .setHisOrderNo(payItem.getHisOrdNum())
                                .addAllDetail(payItem.getItemListList().stream()
                                        .map(i -> OutpatientOrderDetail.newBuilder()
                                                .setItemName(i.getItemName())
                                                .setItemPrice(i.getItemPrice())
                                                .setItemCode(i.getItemCode())
                                                .setItemNumber(i.getItemNumber())
                                                .setItemSpec(i.getItemSpec())
                                                .setItemUnit(i.getItemUnit())
                                                .setItemTotalFee(i.getItemTotalFee())
                                                .build()).collect(Collectors.toList()))
                                .build();
                        BaseResult baseResult = taiheOutpatientServiceBlockingStub.saveOutpatientOrderDetails(sReq);
                        if (baseResult.getCode() != ResultCode.SUCCEED_VALUE) {
                            throw new RuntimeException("保存门诊缴费明细失败");
//                            logger.error("保存门诊缴费明细失败，hisOrderNo : {}", payItem.getHisOrdNum());
                        }
                    }
                }
                break;
            case TYPE_PAID_ZFB:
                switch (hospitalId) {
                    default:
                    case Constants.HOSPITAL_ID_NFYYBYFY:
                        // v1.3.7 白云改为从 HIS 接口读取数据
                        String startDate = request.getStartTime();
                        String endDate = request.getEndTime();
                        Date start = DateUtil.parseDate(startDate, DateUtil.DADE_FROMAT_YMD);
                        Date end = DateUtil.parseDate(endDate, DateUtil.DADE_FROMAT_YMD);
                        CheckUtil.ensureNotNull(start, "参数开始日期有误");
                        CheckUtil.ensureNotNull(end, "参数结束日期有误");
                        GetOutpatientListRequest req3 = GetOutpatientListRequest.newBuilder()
                                .setPatientId(hisPatientId)
                                .setType(TYPE_PAID_WX)
                                .setHospitalId(hospitalId)
                                .setStartDate(startDate)
                                .setEndDate(endDate)
                                .build();
                        GetOutpatientListResponse res3 = taiheServiceBlockingStub.getOutpatientList(req3);
                        if (res3.getCode() != ResultCode.SUCCEED_VALUE) {
                            throw new RuntimeException(res3.getMsg());
                        }
                        for (PaymentItem payItem : res3.getPaymentList()) {
                            PayHistoryResponseData data = new PayHistoryResponseData();
                            data.setStatus(status);
                            data.setTitle("");
                            data.setDepName(payItem.getDeptName());
                            data.setPrescribeDate(payItem.getPrescriptionDate());
                            data.setName(payItem.getPatientName());
                            data.setAmount(String.format("%.2f", payItem.getTotalFee() / 100d));
                            data.setTradeNo(""); //Todo
                            data.setOutTradeNo("");//Todo
                            data.setIdNum("");//Todo
                            data.setInvoiceNo(payItem.getInvoiceNo());
                            data.setHisPatientId(hisPatientId);
                            data.setPayTime(payItem.getPrescriptionDate());
                            list.add(data);
                        }
                        break;
                }
                break;
        }
        Pagination pagination = new Pagination(pageIndex, pageSize, total);
        PageVO<PayHistoryResponseData> res = new PageVO<>(pagination, list);
        return res;
    }

    @Override
    public ComputeSelfPaidOrderResponseData computeSelfPaidOrder(ComputeSelfPaidOrderRequest request) {
        return null;
    }

    @Override
    public ComputeMedicarePayOrderResponseData computeMedicarePayOrder(ComputeMedicarePayOrderRequest request) {
        return null;
    }

    @Override
    public TradeNoForOrderResponseData tradeNoForOrder(TradeNoForOrderRequest request) {
        TradeNoForOrderResponseData data = new TradeNoForOrderResponseData();
        data.setNeedPay(true);//设置是否需要支付宝自费支付
        data.setOutTradeNo("查询订单系统获取订单号");
        data.setTradeNo(null);

        if (data.isNeedPay()) {
            String tradeNo = getTradeNo(request.getAppId(), data.getOutTradeNo());
            data.setTradeNo(tradeNo);
        }
        return data;
    }


    private String getTradeNo(String appId, String outTradeNo) {
        AlipayTradeCreateModel createModel = new AlipayTradeCreateModel();
        createModel.setOutTradeNo(outTradeNo);
        createModel.setTotalAmount("使用真正的系统");
        createModel.setSubject("主题主题");
        createModel.setBuyerId("购买者UID");

        AlipayTradeCreateResponse response = payFace.tradeCreate(appId, createModel);

        if (!StringUtils.isEmpty(response.getOutTradeNo())) {
            return response.getTradeNo();// 获取返回的tradeNO。
        } else {
            throw new RuntimeException("查询交易失败");
        }
    }

    /**
     * 根据身份证或出生日期获取年龄，避免当身份证为空的情况下获取年龄会返回奇怪的值
     *
     * @param idNo     身份证
     * @param birthday 出生年月日，格式 yyyy-MM-dd
     * @return
     */
    private int getPatientAgeSafely(String idNo, String birthday) {
        if (!Checker.isNone(idNo)) {
            return IdCardUtil.getCurrentAge(idNo);
        } else {
//            logger.info("DHOutpatientController#getPatientAgeSafely(birthday = {}): 身份证为空", birthday);
            return IdCardUtil.getCurrentAgeByBirthday(birthday, IdCardUtil.DATE_PATTERN2);
        }
    }
}
