kamft_desktop 0.0.4

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(首次请求后缓存)
pub async fn get_cached_webhook_url() -> &'static str {
    WEBHOOK_URL
        .get_or_init(|| async { WeComGroup::get_wx_webhook_url().await })
        .await
}

/// 发送截图到企业微信的便捷函数(供 screenshot 模块调用)
pub async fn send_to_wecom(images: &[(String, Vec<u8>)]) -> Result<(), String> {
    let group = WeComGroup::default();
    group.send_image_to_wecom(images).await
}

#[derive(Default)]
pub struct WeComGroup {
    pub webhook_url: String,
}

impl WeComGroup {
    /// 从远程配置获取企业微信 Webhook URL
    /// 后端实际返回: {"code":200, "message":"msg", "data":{"key":"...", "data":null}}
    pub async fn get_wx_webhook_url() -> String {
        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
        )
    }
    pub async fn send_msg_to_wecom(&self, content: &str) -> Result<(), String> {
        // 创建 HTTP 客户端
        let client = Axios::builder()
            .timeout(std::time::Duration::from_secs(30))
            .build()
            .map_err(|e| format!("创建 HTTP 客户端失败: {}", e))?;

        // 构造企业微信文本消息体(发送账号信息)
        let body = json::json!({
            "msgtype": "text",
            "text": { "content": content }
        });
        let webhook_url = get_cached_webhook_url().await;
        // 发送消息到企业微信
        let response = client
            .post(webhook_url)
            .json(&body)
            .send()
            .await
            .map_err(|e| format!("发送失败: {}", 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::JsonValue>(&resp_text) {
                let errcode = parsed["errcode"].as_i64().unwrap_or(-1);
                if errcode == 0 {
                    log::info!("企业微信消息发送成功");
                } else {
                    return Err(format!(
                        "企业微信返回错误: errcode={}, errmsg={}",
                        errcode,
                        parsed["errmsg"].as_str().unwrap_or("")
                    ));
                }
            } else {
                log::info!("企业微信消息发送成功 (HTTP {})", status);
            }
        } else {
            return Err(format!("HTTP {} - {}", status, resp_text));
        }

        Ok(())
    }
    /// 发送截图到企业微信 Webhook(base64 + md5)
    pub async fn send_image_to_wecom(&self, 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 = get_cached_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::JsonValue>(&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(())
    }
}