use reqwest::blocking::Client;
use serde_json::Value;
use crate::config::{FirebaseConfig, FirebaseProjectInfo, TestResult};
use crate::firebase::installations::generate_fid;
pub fn test_fcm_send(
client: &Client,
key: &str,
info: &mut FirebaseProjectInfo,
) -> TestResult {
let url = "https://fcm.googleapis.com/fcm/send";
let body = serde_json::json!({
"to": "/topics/__test_nonexistent__",
"data": {"test": "ping"}
});
let resp = match client
.post(url)
.header("Authorization", format!("key={}", key))
.json(&body)
.send()
{
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
if status == 200 {
info.fcm_enabled = Some(true);
let data: Value = resp.json().unwrap_or_default();
let mut result =
TestResult::ok(status, "FCM Legacy API ENABLED — can send push notifications");
if let Some(mid) = data.get("message_id").and_then(|v| v.as_str()) {
result = result.with_extra("message_id", mid);
}
result
} else if status == 401 {
info.fcm_enabled = Some(false);
TestResult::fail(
Some(status),
"Unauthorized",
Some("FCM not authorized for this key (may need server key)".into()),
)
} else {
let text = resp.text().unwrap_or_default();
let detail = if text.is_empty() {
None
} else {
Some(text.chars().take(100).collect())
};
TestResult::fail(Some(status), format!("HTTP {}", status), detail)
}
}
pub fn test_fcm_token_registration(
client: &Client,
config: &FirebaseConfig,
info: &mut FirebaseProjectInfo,
) -> TestResult {
let sender_id = match &config.gcm_sender_id {
Some(id) => id.clone(),
None => {
return TestResult::fail(
None,
"Missing gcm_sender_id",
Some("FCM token registration requires sender ID".into()),
)
}
};
let url = "https://fcmtoken.googleapis.com/register";
let fid = generate_fid();
let app_id = &fid[..11.min(fid.len())];
let params = [
("app", "com.flintbase.test"),
("sender", &sender_id),
("device", "0"),
("app_ver", "1.0.0"),
("gcm_ver", "23.4.0"),
("X-appid", app_id),
("X-scope", "*"),
];
let resp = match client
.post(url)
.header("Authorization", format!("AidLogin {}:0", sender_id))
.form(¶ms)
.send()
{
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
let text = resp.text().unwrap_or_default();
if status == 200 {
if text.starts_with("token=") {
let token = text.splitn(2, '=').nth(1).unwrap_or(&text);
info.fcm_token_obtained = Some(true);
let preview = if token.len() > 50 {
format!("{}...", &token[..50])
} else {
token.to_string()
};
TestResult::ok(status, "FCM token registration endpoint accessible")
.with_extra("token_preview", preview)
} else if text.contains("Error") {
TestResult::fail(
Some(status),
&text,
Some("FCM registration returned error".into()),
)
} else {
TestResult::fail(
Some(status),
format!("HTTP {}", status),
Some(text.chars().take(100).collect()),
)
}
} else {
TestResult::fail(
Some(status),
format!("HTTP {}", status),
Some(text.chars().take(100).collect()),
)
}
}
pub fn test_fcm_v1_api(
client: &Client,
config: &FirebaseConfig,
_info: &mut FirebaseProjectInfo,
) -> TestResult {
let project_id = match &config.project_id {
Some(id) => id.clone(),
None => {
return TestResult::fail(
None,
"No project_id",
Some("FCM v1 requires project ID".into()),
)
}
};
let url = format!(
"https://fcm.googleapis.com/v1/projects/{}/messages:send",
project_id
);
let body = serde_json::json!({
"message": {
"topic": "__test_nonexistent__",
"data": {"test": "ping"}
}
});
let resp = match client
.post(&url)
.header("Authorization", "Bearer invalid_test_token")
.json(&body)
.send()
{
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
let data: Value = resp.json().unwrap_or_default();
if status == 401 {
let error_str = data.get("error").map(|e| e.to_string()).unwrap_or_default();
if error_str.contains("OAuth") || error_str.to_lowercase().contains("authentication") {
return TestResult::ok(
status,
"FCM v1 API exists — requires OAuth (expected)",
);
}
} else if status == 404 {
return TestResult::fail(
Some(status),
"Project not found",
Some("FCM v1 API: project doesn't exist or FCM not enabled".into()),
);
}
let msg = data
.get("error")
.and_then(|e| e.get("message"))
.and_then(|m| m.as_str())
.unwrap_or("")
.to_string();
TestResult::fail(
Some(status),
if msg.is_empty() {
format!("{}", status)
} else {
msg
},
None,
)
}
pub fn test_fcm_topic_management(
client: &Client,
key: &str,
info: &mut FirebaseProjectInfo,
) -> TestResult {
let url = "https://iid.googleapis.com/iid/v1:batchAdd";
let body = serde_json::json!({
"to": "/topics/test_topic",
"registration_tokens": ["invalid_test_token"]
});
let resp = match client
.post(url)
.header("Authorization", format!("key={}", key))
.json(&body)
.send()
{
Ok(r) => r,
Err(e) => return TestResult::fail(None, e.to_string(), None),
};
let status = resp.status().as_u16();
if status == 200 {
info.fcm_topics_accessible = Some(true);
TestResult::ok(status, "FCM topic management API accessible with this key")
} else if status == 401 {
TestResult::fail(
Some(status),
"Unauthorized",
Some("API key not authorized for topic management (may need server key)".into()),
)
} else {
let data: Value = resp.json().unwrap_or_default();
let msg = data
.get("error")
.and_then(|e| e.as_str())
.unwrap_or("")
.to_string();
TestResult::fail(
Some(status),
if msg.is_empty() {
format!("HTTP {}", status)
} else {
msg
},
None,
)
}
}