use std::collections::HashMap;
use crate::{PayMode, PayNotify, RefundNotify, RefundStatus, TradeState, TradeType, Types};
use base64::engine::general_purpose::STANDARD;
use base64::{Engine};
use json::{object, JsonValue};
use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce};
use aes_gcm::aead::{Aead, Payload};
use br_reqwest::Method;


#[derive(Clone, Debug)]
pub struct Wechat {
    /// 服务商APPID
    pub appid: String,
    /// 服务商户号
    pub sp_mchid: String,
    /// 证书号
    pub serial_no: String,
    /// API证书私钥
    pub app_private: String,
    /// APIv3密钥
    pub apikey: String,
    /// APIv2密钥
    pub apiv2: String,
    pub notify_url: String,

}

use chrono::{DateTime, Local, Utc};
use log::{info};
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey};
use openssl::rsa::Rsa;
use openssl::sign::Signer;
use rand::distr::Alphanumeric;
use rand::{rng, Rng};

impl Wechat {
    pub fn http(&mut self, url: &str, method: Method, body: JsonValue) -> Result<JsonValue, String> {
        let sign = self.sign(method.to_str().to_uppercase().as_str(), url, body.to_string().as_str())?;
        let mut http = br_reqwest::Client::new();
        let url = format!("https://api.mch.weixin.qq.com{url}");
        let send = match method {
            Method::GET => http.get(url.as_str()),
            Method::POST => http.post(url.as_str()).raw_json(body),
            _ => http.post(url.as_str()),
        };
        match send.header("Accept", "application/json").header("User-Agent", "api").header("Content-Type", "application/json").header("Authorization", sign.as_str()).send()?.json() {
            Ok(e) => Ok(e),
            Err(e) => Err(e)
        }
    }

    pub fn sign_v2(&mut self, body: JsonValue) -> Result<String, String> {
        let mut map = HashMap::new();
        for (key, value) in body.entries() {
            if key == "sign" {
                continue;
            }
            if value.is_empty() {
                continue;
            }
            map.insert(key, value);
        }
        let mut keys: Vec<_> = map.keys().cloned().collect();
        keys.sort();
        let mut txt = vec![];
        for key in keys {
            txt.push(format!("{}={}", key, map.get(&key).unwrap()));
        }
        let txt = txt.join("&");
        let string_sign_temp = format!("{}&key={}", txt, self.apiv2);

        let sign = br_crypto::md5::encrypt_hex(string_sign_temp.as_bytes()).to_uppercase();
        Ok(sign)
    }

    pub fn sign(&mut self, method: &str, url: &str, body: &str) -> Result<String, String> {
        let timestamp = Utc::now().timestamp(); // 秒级时间戳
        let random_string: String = rng().sample_iter(&Alphanumeric) // 生成随机字母+数字
                                         .take(10) // 指定长度
                                         .map(char::from).collect();

        let sign_txt = format!("{method}\n{url}\n{timestamp}\n{random_string}\n{body}\n");
        if self.app_private.contains("-----BEGIN PRIVATE KEY-----") {
            self.app_private = self.app_private.replace("-----BEGIN PRIVATE KEY-----", "");
            self.app_private = self.app_private.replace("-----END PRIVATE KEY-----", "");
            self.app_private = self.app_private.replace(" ", "");
            self.app_private = self.app_private.replace("\n", "");
            self.app_private = self.app_private.trim().to_string();
        }
        let mut formatted = String::from("-----BEGIN PRIVATE KEY-----\n");
        for chunk in self.app_private.as_bytes().chunks(64) {
            formatted.push_str(&String::from_utf8_lossy(chunk));
            formatted.push('\n');
        }
        formatted.push_str("-----END PRIVATE KEY-----\n");
        self.app_private = formatted;

        // 加载 RSA 私钥
        let rsa = match Rsa::private_key_from_pem(self.app_private.as_bytes()) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("加载RSA私钥失败: {e}"));
            }
        };
        let pkey = match PKey::from_rsa(rsa) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to create PKey: {e}"))
            }
        };
        // 创建签名器
        let mut signer = match Signer::new(MessageDigest::sha256(), &pkey) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to create signer:{e}"));
            }
        };
        // 输入待签名数据
        match signer.update(sign_txt.as_bytes()) {
            Ok(_) => {}
            Err(e) => {
                return Err(e.to_string())
            }
        };
        // 生成签名
        let signature = match signer.sign_to_vec() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to sign: {e}"));
            }
        };
        let signature_b64 = STANDARD.encode(signature);
        let sign = format!(
            r#"WECHATPAY2-SHA256-RSA2048 mchid="{}",nonce_str="{random_string}",signature="{signature_b64}",timestamp="{timestamp}",serial_no="{}""#,
            self.sp_mchid.as_str(),
            self.serial_no
        );
        Ok(sign)
    }

    pub fn paysign(&mut self, prepay_id: &str) -> Result<JsonValue, String> {
        let timestamp = Utc::now().timestamp(); // 秒级时间戳
        let random_string: String = rng().sample_iter(&Alphanumeric) // 生成随机字母+数字
                                         .take(10) // 指定长度
                                         .map(char::from).collect();

        let sign_txt = format!(
            "{}\n{timestamp}\n{random_string}\n{prepay_id}\n",
            self.appid
        );

        // 加载 RSA 私钥
        let rsa = match Rsa::private_key_from_pem(self.app_private.as_bytes()) {
            Ok(e) => e,
            Err(e) => {
                return Err(e.to_string())
            }
        };
        let pkey = match PKey::from_rsa(rsa) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to create PKey: {e}"))
            }
        };
        // 创建签名器
        let mut signer = match Signer::new(MessageDigest::sha256(), &pkey) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to create signer:{e}"));
            }
        };
        // 输入待签名数据
        match signer.update(sign_txt.as_bytes()) {
            Ok(_) => {}
            Err(e) => {
                return Err(e.to_string())
            }
        };
        // 生成签名
        let signature = match signer.sign_to_vec() {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("Failed to sign: {e}"));
            }
        };
        let signature_b64 = STANDARD.encode(signature);
        let sign = signature_b64;
        Ok(object! {
            timeStamp:timestamp,
            nonceStr:random_string,
            package:prepay_id,
            signType:"RSA",
            paySign:sign
        })
    }
}
impl PayMode for Wechat {
    fn check(&mut self) -> Result<bool, String> {
        let timestamp = Utc::now().timestamp(); // 获取微秒级时间戳
        let now = Local::now();
        let formatted = now.format("%Y%m%d").to_string();
        let order_no = format!("test_{formatted}_{timestamp}");
        match self.clone().pay("", Types::MiniJsapi, self.sp_mchid.as_str(), order_no.as_str(), "测试", 0.01, "") {
            Ok(_) => Ok(true),
            Err(e) => {
                if e.contains("受理机构发起支付时, 子商户mchid不能与自身mchid相同") {
                    return Ok(true);
                }
                Ok(false)
            }
        }
    }

    fn get_sub_mchid(&mut self, sub_mchid: &str) -> Result<JsonValue, String> {
        let url = format!("/v3/apply4sub/sub_merchants/{sub_mchid}/settlement");
        let res = self.http(url.as_str(), Method::GET, "".into())?;
        if res.has_key("verify_result") && res["verify_result"] == "VERIFY_SUCCESS" {
            return Ok(true.into());
        }
        Err(res.to_string())
    }


    fn config(&mut self) -> JsonValue {
        todo!()
    }


    fn pay(&mut self, _channel: &str, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String> {
        let url = match types {
            Types::Jsapi => "/v3/pay/partner/transactions/jsapi",
            Types::Native => "/v3/pay/partner/transactions/native",
            Types::H5 => "/v3/pay/partner/transactions/h5",
            Types::MiniJsapi => "/v3/pay/partner/transactions/jsapi",
            Types::App => "/v3/pay/partner/transactions/app",
            Types::Micropay => "/pay/micropay"
        };
        let total = format!("{:.0}", total_fee * 100.0);
        let mut body = object! {
            "sp_appid" => self.appid.clone(),
            "sp_mchid"=> self.sp_mchid.clone(),
            "sub_mchid"=> sub_mchid,
            "description"=>description,
            "out_trade_no"=>out_trade_no,
            "notify_url"=>self.notify_url.clone(),
            "support_fapiao"=>true,
            "amount"=>object! {
                total: total.parse::<i64>().unwrap(),
                currency:"CNY"
            }
        };
        match types {
            Types::Native => {}
            _ => {
                body["payer"] = object! {
                sp_openid:sp_openid
            };
            }
        };
        match self.http(url, Method::POST, body) {
            Ok(e) => {
                match types {
                    Types::Native => {
                        if e.has_key("code_url") {
                            Ok(e["code_url"].clone())
                        } else {
                            Err(e["message"].to_string())
                        }
                    }
                    Types::Jsapi | Types::MiniJsapi => {
                        if e.has_key("prepay_id") {
                            let signinfo = self.paysign(format!("prepay_id={}", e["prepay_id"]).as_str())?;
                            Ok(signinfo)
                        } else {
                            Err(e["message"].to_string())
                        }
                    }
                    _ => {
                        Ok(e)
                    }
                }
            }
            Err(e) => Err(e),
        }
    }

    fn micropay(&mut self, _channel: &str, auth_code: &str, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, org_openid: &str, ip: &str) -> Result<JsonValue, String> {
        let url = "/pay/micropay";
        let total = format!("{:.0}", total_fee * 100.0);

        let nonce_str: String = rand::rng().sample_iter(&Alphanumeric).take(32).map(char::from).collect();

        let mut body = object! {
            "appid": self.appid.clone(),
            "mch_id"=> self.sp_mchid.clone(),
            "sub_mch_id"=> sub_mchid,
            "nonce_str"=>nonce_str,
            "body"=> description,
            "out_trade_no"=>out_trade_no,
            "total_fee"=>total.parse::<i64>().unwrap(),
            "fee_type":"CNY",
            "spbill_create_ip":ip,
            "device_info":org_openid,
            "auth_code":auth_code
        };
        body["sign"] = self.sign_v2(body.clone())?.into();
        let mut xml = vec!["<xml>".to_owned()];
        for (key, value) in body.entries() {
            let t = format!("<{}>{}</{00}>", key, value.clone().clone());
            xml.push(t);
        }
        xml.push("</xml>".to_owned());
        let xml = xml.join("");
        let mut http = br_reqwest::Client::new();

        match http.post(format!("https://api.mch.weixin.qq.com{url}").as_str()).header("Content-Type", "application/xml").raw_xml(xml.into()).send()?.xml() {
            Ok(e) => {
                if e["return_code"].ne("SUCCESS") {
                    return Err(e.to_string());
                }
                if e["result_code"].eq("FAIL") {
                    if e["err_code_des"].ne("需要用户输入支付密码") {
                        return Err(e["err_code_des"].to_string());
                    }
                    let res = PayNotify {
                        trade_type: TradeType::MICROPAY,
                        out_trade_no: out_trade_no.to_string(),
                        sp_mchid: self.sp_mchid.clone(),
                        sub_mchid: sub_mchid.to_string(),
                        sp_appid: e["appid"].to_string(),
                        transaction_id: "".to_string(),
                        success_time: 0,
                        sp_openid: "".to_string(),
                        sub_openid: "".to_string(),
                        total: total_fee,
                        payer_total: total_fee,
                        currency: "CNY".to_string(),
                        payer_currency: "CNY".to_string(),
                        trade_state: TradeState::NOTPAY,
                    };
                    return Ok(res.json());
                }
                let res = PayNotify {
                    trade_type: TradeType::MICROPAY,
                    out_trade_no: out_trade_no.to_string(),
                    sp_mchid: self.sp_mchid.clone(),
                    sub_mchid: sub_mchid.to_string(),
                    sp_appid: e["appid"].to_string(),
                    transaction_id: e["transaction_id"].to_string(),
                    success_time: 0,
                    sp_openid: e["openid"].to_string(),
                    sub_openid: e["openid"].to_string(),
                    total: total_fee,
                    payer_total: total_fee,
                    currency: e["cash_fee_type"].to_string(),
                    payer_currency: "CNY".to_string(),
                    trade_state: TradeState::SUCCESS,
                };
                Ok(res.json())
            }
            Err(e) => Err(e),
        }
    }

    fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
        let url = format!("/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close");
        let body = object! {
            "sp_mchid"=> self.sp_mchid.clone(),
            "sub_mchid"=> sub_mchid
        };
        match self.http(&url, Method::POST, body) {
            Ok(_) => Ok(true.into()),
            Err(e) => Err(e)
        }
    }

    fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
        let url = format!(
            "/v3/pay/partner/transactions/out-trade-no/{}?sub_mchid={}&sp_mchid={}",
            out_trade_no, sub_mchid, self.sp_mchid
        );
        match self.http(&url, Method::GET, "".into()) {
            Ok(e) => {
                if e.has_key("message") {
                    return Err(e["message"].to_string());
                }
                let res = PayNotify {
                    trade_type: TradeType::from(e["trade_type"].to_string().as_str()),
                    out_trade_no: e["out_trade_no"].as_str().unwrap().to_string(),
                    sp_mchid: e["sp_mchid"].as_str().unwrap().to_string(),
                    sub_mchid: e["sub_mchid"].as_str().unwrap().to_string(),
                    sp_appid: e["sp_appid"].as_str().unwrap().to_string(),
                    transaction_id: e["transaction_id"].to_string(),
                    success_time: PayNotify::success_time(e["success_time"].as_str().unwrap_or("")),
                    sp_openid: e["payer"]["sp_openid"].to_string(),
                    sub_openid: e["payer"]["sub_openid"].to_string(),
                    total: e["amount"]["total"].as_f64().unwrap_or(0.0) / 100.0,
                    currency: e["amount"]["currency"].to_string(),
                    payer_total: e["amount"]["payer_total"].as_f64().unwrap_or(0.0) / 100.0,
                    payer_currency: e["amount"]["payer_currency"].to_string(),
                    trade_state: TradeState::from(e["trade_state"].as_str().unwrap()),
                };
                Ok(res.json())
            }
            Err(e) => Err(e),
        }
    }

    fn pay_micropay_query(&mut self, out_trade_no: &str, sub_mchid: &str, _channel: &str) -> Result<JsonValue, String> {
        let nonce_str: String = rand::rng().sample_iter(&Alphanumeric).take(32).map(char::from).collect();
        let mut body = object! {
            "appid": self.appid.clone(),
            "mch_id"=> self.sp_mchid.clone(),
            "sub_mch_id"=> sub_mchid,
            "nonce_str"=>nonce_str,
            "out_trade_no"=>out_trade_no
        };
        body["sign"] = self.sign_v2(body.clone())?.into();
        let mut xml = vec!["<xml>".to_owned()];
        for (key, value) in body.entries() {
            let t = format!("<{}>{}</{00}>", key, value.clone().clone());
            xml.push(t);
        }
        xml.push("</xml>".to_owned());
        let xml = xml.join("");
        let mut http = br_reqwest::Client::new();
        match http.post("https://api.mch.weixin.qq.com/pay/orderquery".to_string().as_str()).header("Content-Type", "application/xml").raw_xml(xml.into()).send()?.xml() {
            Ok(e) => {
                if e.has_key("result_code") && e["result_code"] != "SUCCESS" {
                    info!("pay_micropay_query: {e:#}");
                    return Err(e["return_msg"].to_string());
                }
                if e["trade_state"].eq("USERPAYING") {
                    let res = PayNotify {
                        trade_type: TradeType::MICROPAY,
                        out_trade_no: e["out_trade_no"].as_str().unwrap().to_string(),
                        sp_mchid: e["mch_id"].as_str().unwrap().to_string(),
                        sub_mchid: e["sub_mch_id"].as_str().unwrap().to_string(),
                        sp_appid: e["appid"].as_str().unwrap().to_string(),
                        transaction_id: "".to_string(),
                        success_time: 0,
                        sp_openid: "".to_string(),
                        sub_openid: "".to_string(),
                        total: 0.0,
                        currency: "CNY".to_string(),
                        payer_total: 0.0,
                        payer_currency: "CNY".to_string(),
                        trade_state: TradeState::from(e["trade_state"].as_str().unwrap()),
                    };
                    return Ok(res.json());
                }
                let res = PayNotify {
                    trade_type: TradeType::from(e["trade_type"].to_string().as_str()),
                    out_trade_no: e["out_trade_no"].as_str().unwrap().to_string(),
                    sp_mchid: e["mch_id"].as_str().unwrap().to_string(),
                    sub_mchid: e["sub_mch_id"].as_str().unwrap().to_string(),
                    sp_appid: e["appid"].as_str().unwrap().to_string(),
                    transaction_id: e["transaction_id"].to_string(),
                    success_time: PayNotify::datetime_to_timestamp(e["time_end"].as_str().unwrap_or(""), "%Y%m%d%H%M%S"),
                    sp_openid: e["device_info"].to_string(),
                    sub_openid: e["openid"].to_string(),
                    total: e["total_fee"].to_string().parse::<f64>().unwrap_or(0.0) / 100.0,
                    currency: e["fee_type"].to_string(),
                    payer_total: e["cash_fee"].to_string().parse::<f64>().unwrap_or(0.0) / 100.0,
                    payer_currency: e["cash_fee_type"].to_string(),
                    trade_state: TradeState::from(e["trade_state"].as_str().unwrap()),
                };
                Ok(res.json())
            }
            Err(e) => Err(e)
        }
    }
    fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
        if self.apikey.is_empty() {
            return Err("apikey 不能为空".to_string());
        }
        let key = Key::<Aes256Gcm>::from_slice(self.apikey.as_bytes());
        let cipher = Aes256Gcm::new(key);
        let nonce = Nonce::from_slice(nonce.as_bytes());
        let data = match STANDARD.decode(ciphertext) {
            Ok(e) => e,
            Err(e) => return Err(format!("Invalid data received from API :{e}"))
        };
        // 组合 Payload（带 aad）
        let payload = Payload {
            msg: &data,
            aad: associated_data.as_bytes(),
        };

        // 解密
        let plaintext = match cipher.decrypt(nonce, payload) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("解密 API:{e}"));
            }
        };
        let rr = match String::from_utf8(plaintext) {
            Ok(d) => d,
            Err(_) => return Err("utf8 error".to_string())
        };
        let json = match json::parse(rr.as_str()) {
            Ok(e) => e,
            Err(_) => return Err("json error".to_string())
        };
        let res = PayNotify {
            trade_type: TradeType::from(json["trade_type"].as_str().unwrap()),
            out_trade_no: json["out_trade_no"].as_str().unwrap().to_string(),
            sp_mchid: json["sp_mchid"].as_str().unwrap().to_string(),
            sub_mchid: json["sub_mchid"].as_str().unwrap().to_string(),
            sp_appid: json["sp_appid"].as_str().unwrap().to_string(),
            transaction_id: json["transaction_id"].as_str().unwrap().to_string(),
            success_time: PayNotify::success_time(json["success_time"].as_str().unwrap_or("")),
            sp_openid: json["payer"]["sp_openid"].as_str().unwrap().to_string(),
            sub_openid: json["payer"]["sub_openid"].as_str().unwrap().to_string(),
            total: json["amount"]["total"].to_string().parse::<f64>().unwrap_or(0.0) / 100.0,
            payer_total: json["amount"]["payer_total"].to_string().parse::<f64>().unwrap_or(0.0) / 100.0,
            currency: json["amount"]["currency"].to_string(),
            payer_currency: json["amount"]["payer_currency"].to_string(),
            trade_state: TradeState::from(json["trade_state"].as_str().unwrap()),
        };
        Ok(res.json())
    }

    fn refund(
        &mut self,
        sub_mchid: &str,
        out_trade_no: &str,
        transaction_id: &str,
        out_refund_no: &str,
        amount: f64,
        total: f64,
        currency: &str,
    ) -> Result<JsonValue, String> {
        let url = "/v3/refund/domestic/refunds";

        let refund = format!("{:.0}", amount * 100.0);
        let total = format!("{:.0}", total * 100.0);

        let body = object! {
            "sub_mchid"=> sub_mchid,
            "transaction_id"=>transaction_id,
            "out_trade_no"=>out_trade_no,
            "out_refund_no"=>out_refund_no,
            "amount"=>object! {
                refund: refund.parse::<i64>().unwrap(),
                total: total.parse::<i64>().unwrap(),
                currency:currency
            }
        };
        match self.http(url, Method::POST, body) {
            Ok(e) => {
                if e.is_empty() {
                    return Err("已执行".to_string());
                }
                if e.has_key("message") {
                    return Err(e["message"].to_string());
                }
                let mut refund_time = 0.0;
                if e.has_key("success_time") {
                    let success_time = e["success_time"].as_str().unwrap_or("").to_string();
                    if !success_time.is_empty() {
                        let datetime = DateTime::parse_from_rfc3339(success_time.as_str()).unwrap();
                        refund_time = datetime.timestamp() as f64;
                    }
                }

                let status = match e["status"].as_str().unwrap() {
                    "PROCESSING" => "退款中",
                    "SUCCESS" => "已退款",
                    _ => "无退款",
                };
                let info = object! {
                    refund_id: e["refund_id"].clone(),
                    user_received_account:e["user_received_account"].clone(),
                    status:status,
                    refund_time:refund_time,
                    out_refund_no: e["out_refund_no"].clone(),
                };
                Ok(info)
            }
            Err(e) => Err(e)
        }
    }

    fn micropay_refund(&mut self, sub_mchid: &str, out_trade_no: &str, transaction_id: &str, out_refund_no: &str, amount: f64, total: f64, currency: &str, refund_text: &str) -> Result<JsonValue, String> {
        let refund = format!("{:.0}", amount * 100.0);
        let total = format!("{:.0}", total * 100.0);


        let nonce_str: String = rand::rng().sample_iter(&Alphanumeric).take(32).map(char::from).collect();
        let mut body = object! {
            "appid": self.appid.clone(),
            "mch_id"=> self.sp_mchid.clone(),
            "sub_mch_id"=> sub_mchid,
            "nonce_str"=>nonce_str,
            "out_trade_no"=>out_trade_no,
            "transaction_id"=>transaction_id,
            "out_refund_no"=>out_refund_no,
            "total_fee"=>total,
            "refund_fee"=>refund,
            "refund_fee_type"=> currency,
            "refund_desc"=>refund_text
        };
        body["sign"] = self.sign_v2(body.clone())?.into();
        let mut xml = vec!["<xml>".to_owned()];
        for (key, value) in body.entries() {
            let t = format!("<{}>{}</{00}>", key, value.clone().clone());
            xml.push(t);
        }
        xml.push("</xml>".to_owned());
        let xml = xml.join("");
        let mut http = br_reqwest::Client::new();
        match http.post("https://api.mch.weixin.qq.com/secapi/pay/refund".to_string().as_str()).header("Content-Type", "application/xml").raw_xml(xml.into()).send()?.xml() {
            Ok(e) => {
                println!("{e:#}");
                if !e.has_key("status") {
                    return Err(e.to_string());
                }
                if e.is_empty() {
                    return Err("已执行".to_string());
                }
                if e.has_key("message") {
                    return Err(e["message"].to_string());
                }
                let mut refund_time = 0.0;
                if e.has_key("success_time") {
                    let success_time = e["success_time"].as_str().unwrap_or("").to_string();
                    if !success_time.is_empty() {
                        let datetime = DateTime::parse_from_rfc3339(success_time.as_str()).unwrap();
                        refund_time = datetime.timestamp() as f64;
                    }
                }

                let status = match e["status"].as_str().unwrap() {
                    "PROCESSING" => "退款中",
                    "SUCCESS" => "已退款",
                    _ => "无退款",
                };
                let info = object! {
                    refund_id: e["refund_id"].clone(),
                    user_received_account:e["user_received_account"].clone(),
                    status:status,
                    refund_time:refund_time,
                    out_refund_no: e["out_refund_no"].clone(),
                };
                Ok(info)
            }
            Err(e) => Err(e),
        }
    }

    fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
        if self.apikey.is_empty() {
            return Err("apikey 不能为空".to_string());
        }
        let key = Key::<Aes256Gcm>::from_slice(self.apikey.as_bytes());
        let cipher = Aes256Gcm::new(key);
        let nonce = Nonce::from_slice(nonce.as_bytes());
        let data = match STANDARD.decode(ciphertext) {
            Ok(e) => e,
            Err(e) => return Err(format!("Invalid data received from API :{e}"))
        };
        // 组合 Payload（带 aad）
        let payload = Payload {
            msg: &data,
            aad: associated_data.as_bytes(),
        };

        // 解密
        let plaintext = match cipher.decrypt(nonce, payload) {
            Ok(e) => e,
            Err(e) => {
                return Err(format!("解密 API:{e}"));
            }
        };
        let rr = match String::from_utf8(plaintext) {
            Ok(d) => d,
            Err(_) => return Err("utf8 error".to_string())
        };
        let json = match json::parse(rr.as_str()) {
            Ok(e) => e,
            Err(_) => return Err("json error".to_string())
        };
        let res = RefundNotify {
            out_trade_no: json["out_trade_no"].to_string(),
            refund_no: json["out_refund_no"].to_string(),
            refund_id: json["refund_id"].to_string(),
            sp_mchid: json["sp_mchid"].as_str().unwrap().to_string(),
            sub_mchid: json["sub_mchid"].as_str().unwrap().to_string(),
            transaction_id: json["transaction_id"].as_str().unwrap().to_string(),
            success_time: PayNotify::success_time(json["success_time"].as_str().unwrap_or("")),
            total: json["amount"]["total"].as_f64().unwrap_or(0.0) / 100.0,
            refund: json["amount"]["refund"].as_f64().unwrap_or(0.0) / 100.0,
            payer_total: json["amount"]["payer_total"].as_f64().unwrap() / 100.0,
            payer_refund: json["amount"]["payer_refund"].as_f64().unwrap() / 100.0,
            status: RefundStatus::from(json["refund_status"].as_str().unwrap()),
        };
        Ok(res.json())
    }

    fn refund_query(&mut self, _trade_no: &str, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
        let url = format!("/v3/refund/domestic/refunds/{out_refund_no}?sub_mchid={sub_mchid}");
        match self.http(&url, Method::GET, "".into()) {
            Ok(e) => {
                if e.is_empty() {
                    return Err("已执行".to_string());
                }
                if e.has_key("message") {
                    return Err(e["message"].to_string());
                }


                let res = RefundNotify {
                    out_trade_no: e["out_trade_no"].to_string(),
                    refund_no: e["out_refund_no"].to_string(),
                    sp_mchid: "".to_string(),
                    sub_mchid: sub_mchid.to_string(),
                    transaction_id: e["transaction_id"].to_string(),
                    refund_id: e["refund_id"].to_string(),
                    success_time: PayNotify::success_time(e["success_time"].as_str().unwrap_or("")),
                    total: e["amount"]["total"].to_string().parse::<f64>().unwrap(),
                    payer_total: e["amount"]["total"].to_string().parse::<f64>().unwrap(),
                    refund: e["amount"]["refund"].to_string().parse::<f64>().unwrap(),
                    payer_refund: e["amount"]["refund"].to_string().parse::<f64>().unwrap(),
                    status: RefundStatus::from(e["status"].as_str().unwrap()),
                };

                Ok(res.json())
            }
            Err(e) => Err(e),
        }
    }

    fn incoming(&mut self, business_code: &str, contact_info: JsonValue, _subject_info: JsonValue, _business_info: JsonValue, _settlement_info: JsonValue, _bank_account_info: JsonValue) -> Result<JsonValue, String> {
        let contact_info_data = object! {
            // 超级管理员类型 LEGAL: 经营者/法人 SUPER: 经办人
            contact_type:contact_info["contact_type"].clone(),
            contact_name:contact_info["contact_name"].clone(),
        };

        let body = object! {
            business_code:business_code,
            contact_info:contact_info_data
        };
        println!("{body:#}");
        match self.http("/v3/applyment4sub/applyment/", Method::POST, body) {
            Ok(e) => {
                println!("{e:#}");
                if e.is_empty() {
                    return Err("已执行".to_string());
                }
                if e.has_key("message") {
                    return Err(e["message"].to_string());
                }
                Ok(e)
            }
            Err(e) => Err(e),
        }
    }
}
