kamft_desktop 0.0.1

Kamft desktop utilities including screenshot capture and WeChat Work integration
use crate::core::{
    axios::Axios,
    base64::{Engine, BASE64},
    json, log, ApiResp, RespData,
};
use tokio::sync::OnceCell;

/// 缓存 Webhook URL,只请求一次远程配置
static WEBHOOK_URL: OnceCell<String> = OnceCell::const_new();

/// 从远程配置获取企业微信 Webhook URL(首次请求后缓存)
/// 后端实际返回: {"code":200, "message":"msg", "data":{"key":"...", "data":null}}
pub async fn get_wx_webhook_url() -> &'static str {
    WEBHOOK_URL
        .get_or_init(|| async {
            let resp = Axios::new()
                .post("https://www.kamft.cn/allow/getcfg")
                .json(&json::json!("wxwork"))
                .send()
                .await
                .expect("请求配置失败");

            let data = resp
                .json::<ApiResp<RespData>>()
                .await
                .expect("解析配置响应失败");
            log::info!("get_wx_webhook_url解析配置响应: {:?}", data);
            format!(
                "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={}",
                data.data.key
            )
        })
        .await
}

/// 发送截图到企业微信 Webhook(base64 + md5)
pub async fn send_to_wecom(images: &[(String, Vec<u8>)]) -> Result<(), String> {
    if images.is_empty() {
        return Err("没有需要发送的截图".into());
    }

    let client = Axios::builder()
        .timeout(std::time::Duration::from_secs(30))
        .build()
        .map_err(|e| format!("创建 HTTP 客户端失败: {}", e))?;

    let webhook_url: &str = get_wx_webhook_url().await;

    for (label, bytes) in images {
        // 计算原始数据的 MD5
        let md5_hex = format!("{:x}", md5::compute(bytes));

        // Base64 编码
        let base64_str = BASE64.encode(bytes);

        // 构造企业微信图片消息体
        let body = json::json!({
            "msgtype": "image",
            "image": {
                "base64": base64_str,
                "md5": md5_hex,
            }
        });

        let response = client
            .post(webhook_url)
            .json(&body)
            .send()
            .await
            .map_err(|e| format!("发送失败 ({}): {}", label, e))?;

        let status = response.status();
        let resp_text = response.text().await.unwrap_or_default();

        if status.is_success() {
            if let Ok(parsed) = json::from_str::<json::Value>(&resp_text) {
                let errcode = parsed["errcode"].as_i64().unwrap_or(-1);
                if errcode == 0 {
                    log::info!("发送成功: {}", label);
                } else {
                    log::warn!(
                        "发送失败 ({}): errcode={}, errmsg={}",
                        label,
                        errcode,
                        parsed["errmsg"].as_str().unwrap_or("")
                    );
                }
            } else {
                log::info!("发送成功: {} (HTTP {})", label, status);
            }
        } else {
            log::warn!("发送失败 ({}): HTTP {} - {}", label, status, resp_text);
        }
    }

    Ok(())
}