package com.ywt.alipaympapi.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.CommerceAppUploadRequestContent;
import com.alipay.api.request.AlipayCommerceAppAuthUploadRequest;
import com.alipay.api.response.AlipayCommerceAppAuthUploadResponse;
import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
import com.alipay.easysdk.factory.Factory;
import com.ywt.alipaympapi.core.utils.CheckUtil;
import com.ywt.alipaympapi.core.utils.DateUtil;
import com.ywt.alipaympapi.face.impl.AlipayService;
import com.ywt.alipaympapi.models.Constants;
import com.ywt.core.exception.AppMessageException;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.bcel.Const;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCommands;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;

/**
 * 支付宝“智能”消息服务
 * 参考文档 <a href="https://opendocs.alipay.com/pre-open/01odaz">医疗小程序智能消息推送接入方案</a>
 *
 * @author Walker
 * Created on 2022/9/28
 */
@Slf4j
@Service
public class MessageService {
    @Autowired
    AlipayService alipayService;
    @Autowired
    JedisCommands jedisCommands;

    /**
     * 小程序用 authCode 换取 accessToken
     */
    public String getAccessToken(String authCode) {
        String accessToken = "";
        try {
            AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken(authCode);
            log.info("MessageService#getAccessToken(authCode={} ):\n {}", authCode, JSON.toJSONString(response));
            accessToken = response.getAccessToken();
        } catch (Exception e) {
            log.error("MessageService#getAccessToken(authCode={} ):\n {}", authCode, e.getMessage(), e);
        }
        return accessToken;
    }

    /**
     * 发送“智能”消息
     *
     * @param appId    小程序 appId
     * @param alipayUid 支付宝用户 id
     * @param jsonBody 业务参数，具体根据业务类型按照文档拼接
     */
    public void sendIntelliMsg(String appId, String alipayUid, JSONObject jsonBody) {
        try {
            String rk = String.format(Constants.RK_ACCESS_TOKEN, appId, alipayUid);
            String accessToken = jedisCommands.get(rk);
            CheckUtil.ensureNotEmpty(accessToken, rk + " 无法获取 accessToken");
            AlipayCommerceAppAuthUploadRequest request = new AlipayCommerceAppAuthUploadRequest();
            request.setServiceName("alipay.commerce.app.data");//应用服务名称 固定值 String(256) 不可空
            request.setTargetId("2088441565011410"); //目标用户 String(64) 签约商家 PID 不可空

            CommerceAppUploadRequestContent content = new CommerceAppUploadRequestContent(); //服务数据参数
            content.setTenantAppId("20220815114100017389"); //租户应 用ID String(64) 支付宝分配 不可空
            content.setActivityId("upload_hospital_order"); //业务流程ID String(64) 不可空 此处固定为“upload_hospital_order”

            content.setBody(JSONObject.toJSONString(jsonBody));
            request.setContent(content);
            log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 入参：{}", appId, accessToken, JSON.toJSONString(request));

            AlipayCommerceAppAuthUploadResponse response = alipayService.getAlipayClient(appId).execute(request, accessToken);
            log.info("MessageService#sendIntelliMsg(appId={}, accessToken={} ): 响应：{}", appId, accessToken, JSON.toJSONString(response));
        } catch (AppMessageException e) {
            log.error("MessageService#sendIntelliMsg(): 业务异常：{}", e.getMessage());
        } catch (Exception e) {
            log.error("MessageService#sendIntelliMsg(appId={} , jsonBody={} , alipayUid={} ):\n {}", appId, jsonBody, alipayUid, e.getMessage(), e);
        }
    }

    /**
     * 发送预约挂号单消息
     */
    public void sendRegMsg(int orderId, String orderNo, String alipayUid, String orderCreateTime, String orderAmountStr,
                           String tradeNo, String hospitalName, String deptName, String doctorName, String doctorId,
                           String patientName, String regDate, String deptLoc, String appId, String merchantOrderStatus,
                           String isvPid) throws AppMessageException {
        CheckUtil.ensureNotEmpty(deptLoc, "科室位置不能为空");
        // 医院登记号
        String hospRegId = "352790440111410131";
        // 小程序跳转路径
        String pathParam = "";
        try {
            pathParam = URLEncoder.encode(String.format("?header=show&orderId=%d&pageType=appointment-result&title=挂号详情", orderId), "utf-8");
        } catch (UnsupportedEncodingException e) {
            log.error("MessageService#sendRegMsg UnsupportedEncodingException: {}", e.getMessage(), e);
        }
        String mpPath = String.format("alipays://platformapi/startapp?appId=%s&page=antbuilder/industry/hospitalV2/pages/page-no-pull/index%s", appId, pathParam);
        JSONObject jsonBody = new JSONObject(); //业务流程参数 String(6000) 业务流程请求参数说明
        jsonBody.put("out_biz_no", orderNo);//医院预约单订单号 唯一不重复(同一 家 ISV 接入的所有 医院的挂号单、检 查号、医药单都不 可重复) String(128)
        jsonBody.put("partner_id", isvPid); //ISV的PID，支付宝id（2088 开头）。同一家ISV 请保持一致！
        jsonBody.put("buyer_id", alipayUid);//就诊人 id，授权 人id 就诊人在支付宝平 台的 2088 开头 16 位id
        jsonBody.put("tiny_app_id", appId);//医院在支付宝的小 程序id
        jsonBody.put("order_create_time", orderCreateTime);//订单创建时间
        jsonBody.put("order_modified_time", DateUtil.formatDate(new Date(), ""));//订单修改时间
        jsonBody.put("amount", orderAmountStr);//订单金额
        jsonBody.put("pay_amount", orderAmountStr);//支付金额
        jsonBody.put("trade_no", tradeNo);//支付宝交易号
        jsonBody.put("order_type", "HOSPITAL_ORDER"); // 固定为 HOSPITAL_ORDER
        jsonBody.put("out_biz_type", "HOSPITAL_APPOINTMENT"); // 固定值 HOSPITAL_APPOINTMENT
        // 状态文档：https://gw.alipayobjects.com/os/bmw-prod/05064ae2-e3c7-4e6c-93ed-ad4740b66000.pdf
        // MERCHANT PREORDER SUCCESS 预约成功
        // MERCHANT NUM TAKEN 己取号
        // MERCHANT WAIT CHECK IN 待签到
        // MERCHANT CALL NUM 叫号中
        // MERCHANT NUM ARRIVED 己到号
        // MERCHANT NUM PASSED 已过号
        // MERCHANT FINISHED 已完成
        // MERCHANT CLOSED 已取消
        // MERCHANT REFUNDED 已退款
        jsonBody.put("merchant_order_status", merchantOrderStatus); //状态 String(64) 枚举详见文档
        JSONArray itemOrderList = new JSONArray();
        JSONObject itemOrder = new JSONObject();
        itemOrder.put("item_name", "预约挂号");//商品名称
        itemOrder.put("quantity", "1");//商品数量
        itemOrder.put("sku_id", "1"); //商品 skuId
        itemOrder.put("unit_price", orderAmountStr);//商品单价
        itemOrderList.add(itemOrder);
        jsonBody.put("item_order_list", itemOrderList);

        JSONObject extInfo = new JSONObject();
        extInfo.put("hospital", hospitalName);//医院名称
        extInfo.put("hospital_register_id", hospRegId);//医院登记号
        extInfo.put("department", deptName);//就诊科室
        extInfo.put("dept_num", "");//诊室编号
        extInfo.put("dept_loc", deptLoc);//科室位置
        extInfo.put("navigation", "");//导航地址
        extInfo.put("doctor", doctorName);//医生名称
        extInfo.put("doctor_rank", "");//医生职级
        extInfo.put("doctor_id", doctorId);//医生 id
        extInfo.put("doctor_avatar", "");//医生头像 url
        extInfo.put("patient", patientName);//就诊人  必须与 buy_id 对 应的姓名一致
        extInfo.put("scheduled_time", regDate);//预约时间
        extInfo.put("take_num_url", "");//取号入口
        extInfo.put("take_num_password", "");//取号密码
        extInfo.put("call_num_url", "");//叫号进度入口
        extInfo.put("medical_order_id", "");//就诊单id
        extInfo.put("medical_num", "");//就诊/检 查序号
        extInfo.put("merchant_order_link_page", mpPath);//订单链接
        jsonBody.put("ext_info", extInfo);

        sendIntelliMsg(appId, alipayUid, jsonBody);
    }
}
