package com.ruoyi.common.pay.xy.service;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.PayApi;
import com.ruoyi.common.pay.Payable;
import com.ruoyi.common.pay.Refundable;
import com.ruoyi.common.pay.xy.config.XyPayConfig;
import com.ruoyi.common.pay.xy.constants.XyPayConstants;
import com.ruoyi.common.pay.xy.utils.HttpUtil;
import com.ruoyi.common.pay.xy.utils.XyPayUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
import java.util.TreeMap;

/**
 * @author wjh
 * 2025/1/8
 */
@Service
@Slf4j
public class XyWxPayService implements PayApi {
    @Override
    public Object pay(Payable payable, Object config) {
        XyPayConfig payConfig = (XyPayConfig) config;

        // 请求地址
        String url = payConfig.getHost() + "/yyfsevr/order/pay";

        // 请求参数
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("agetId", payConfig.getAgetId());
        params.put("custId", payConfig.getCustId());
        params.put("orderNo", payable.payableOutTradeNo());
        params.put("txamt", payable.payableFen());
        params.put("openid", payable.payableOpenId());
        params.put("payWay", XyPayConstants.PAY_WAY_WX);
        params.put("traType", XyPayConstants.TRA_TYPE_MINI_PROGRAM);
        params.put("wxAppid", payConfig.getAppId());
        params.put("ip", payable.payableIp());
        params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
        params.put("version", "1.0.0");

        // 参数签名
        params.put("sign", XyPayUtil.encrypt(params, payConfig.getPublicKey()));

        // 发送请求
        try {
            String response = HttpUtil.postData(url, params);
            ServiceUtil.assertion(response == null, "响应结果为空");
            JSONObject json = JSONObject.parseObject(response);
            String code = json.getString("code");
            ServiceUtil.assertion(!Objects.equals("000000", code), json.getString("msg"));

            JSONObject data = json.getJSONObject("data");
            ServiceUtil.assertion(data == null, "响应数据为空");
            PrepayWithRequestPaymentResponse result = new PrepayWithRequestPaymentResponse();
            result.setAppId(data.getString("jsapiAppid"));
            result.setTimeStamp(data.getString("jsapiTimestamp"));
            result.setNonceStr(data.getString("jsapiNoncestr"));
            result.setPackageVal(data.getString("jsapiPackage"));
            result.setSignType(data.getString("jsapiSignType"));
            result.setPaySign(data.getString("jsapiPaySign"));
            return result;
        } catch (Exception e)  {
            throw new ServiceException("支付请求失败：" + e.getMessage());
        }
    }

    @Override
    public void closeByOutTradeNo(String outTradeNo, Object config) {
        XyPayConfig payConfig = (XyPayConfig) config;

        // 请求地址
        String url = payConfig.getHost() + "/yyfsevr/order/closePay";

        // 请求参数
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("agetId", payConfig.getAgetId());
        params.put("custId", payConfig.getCustId());
        params.put("threeOrderNO", outTradeNo);
        params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
        params.put("version", "1.0.0");

        // 参数签名
        params.put("sign", XyPayUtil.encrypt(params, payConfig.getPublicKey()));

        // 发送请求
        try {
            String response = HttpUtil.postData(url, params);
            ServiceUtil.assertion(response == null, "响应结果为空");
            JSONObject json = JSONObject.parseObject(response);
            String code = json.getString("code");
            ServiceUtil.assertion(!Objects.equals("000000", code), json.getString("msg"));
            JSONObject data = json.getJSONObject("data");
            ServiceUtil.assertion(data == null, "响应数据为空");
            ServiceUtil.assertion(!Objects.equals(data.getString("closeFlag"), "1"), "尝试关单失败");
        } catch (Exception e)  {
            throw new ServiceException("关单失败：" + e.getMessage());
        }
    }

    @Override
    public Object queryByOutTradeNo(String outTradeNo, LocalDate orderDate, Object config) {
        XyPayConfig payConfig = (XyPayConfig) config;

        // 请求地址
        String url = payConfig.getHost() + "/yyfsevr/order/orderQuery";

        // 请求参数
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("agetId", payConfig.getAgetId());
        params.put("custId", payConfig.getCustId());
        params.put("orderNo", outTradeNo);
        params.put("orderTime", DateUtils.format(orderDate, "yyyyMMdd"));
        params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
        params.put("version", "1.0.0");

        // 参数签名
        params.put("sign", XyPayUtil.encrypt(params, payConfig.getPublicKey()));

        // 发送请求
        try {
            String response = HttpUtil.postData(url, params);
            ServiceUtil.assertion(response == null, "响应结果为空");
            return JSONObject.parseObject(response);
        } catch (Exception e)  {
            throw new ServiceException("查询支付单失败：" + e.getMessage());
        }
    }

    @Override
    public Object refund(Refundable refundAble, Object config) {

        XyPayConfig payConfig = (XyPayConfig) config;

        // 请求地址
        String url = payConfig.getHost() + "/yyfsevr/order/refund";

        // 请求参数
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("agetId", payConfig.getAgetId());
        params.put("custId", payConfig.getCustId());
        params.put("orderNo", refundAble.refundOutRefundNo());
        params.put("oldTOrderNo", refundAble.refundOutTradeNo());
        params.put("refundAmount", refundAble.refundAmountFen());
        params.put("tag", XyPayConstants.TAG_WX);

        params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
        params.put("version", "1.0.0");

        // 参数签名
        params.put("sign", XyPayUtil.encrypt(params, payConfig.getPublicKey()));

        // 发送请求
        try {
            String response = HttpUtil.postData(url, params);
            ServiceUtil.assertion(response == null, "响应结果为空");
            JSONObject json = JSONObject.parseObject(response);
            String code = json.getString("code");
            ServiceUtil.assertion(!Objects.equals("000000", code), json.getString("msg"));

            return json.getJSONObject("data");
        } catch (Exception e)  {
            throw new ServiceException("退款失败：" + e.getMessage());
        }
    }

    @Override
    public boolean isPaySuccessByOutTradeNo(String outTradeNo, LocalDate orderDate, Object config) {
        Object result = this.queryByOutTradeNo(outTradeNo, orderDate, config);
        return isPaySuccess(result);
    }

    @Override
    public boolean isPaySuccess(Object result) {
        if (result == null) {
            return false;
        }
        JSONObject json = (JSONObject) result;
        return Objects.equals("000000", json.getString("code")) ;
    }

    @Override
    public LocalDateTime getPayTime(Object result) {
        if (result == null) {
            return null;
        }
        JSONObject json = (JSONObject) result;
        JSONObject data = json.getJSONObject("data");
        if (data == null) {
            return null;
        }
        return DateUtils.toLocalDateTime(data.getString("orderTime"), "yyyyMMddHHmmss");
    }

    /**
     * 关联商户号和机构
     * @return
     */
    public boolean connectCust(XyPayConfig config) {
        // 请求地址
        String url = config.getHost() + "/yyfsevr/order/connectCust";

        // 请求参数
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("agetId", config.getAgetId());
        params.put("custId", config.getCustId());
        params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
        params.put("version", "1.0.0");

        // 参数签名
        params.put("sign", XyPayUtil.encrypt(params, config.getPublicKey()));

        // 发送请求
        try {
            String response = HttpUtil.postData(url, params);
            ServiceUtil.assertion(response == null, "响应结果为空");
            JSONObject json = JSONObject.parseObject(response);
            String code = json.getString("code");

            // 000003 已关联，请勿重复关联，000000 成功
            ServiceUtil.assertion(!Arrays.asList("000003", "000000").contains(code), json.getString("msg"));
            return true;
        } catch (Exception e) {
            log.error("请求失败：" + e.getMessage());
            return false;
        }

    }
}
