iphone 0.1.0

Return the latest iPhone model, price (USD), and release date.
Documentation
use regex::Regex;

pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

pub struct LatestIphone {
    pub model: String,
    pub price_usd: Option<u32>,
    pub release_date: Option<String>, // YYYY-MM-DD
}

/// 返回最新版 iPhone 的型号、美元起售价、以及发布日期(发布会公布日期)。
pub fn latest() -> LatestIphone {
    LatestIphone {
        // 作为离线/抓取失败时的回退值
        model: "iPhone 17".to_string(),
        price_usd: Some(799),
        release_date: Some("2025-09-09".to_string()),
    }
}

/// 动态抓取最新版 iPhone 信息(型号、美元起售价、发布日期)。
/// 抓取失败时返回 `latest()` 的回退值。
pub fn fetch_latest() -> Result<LatestIphone, String> {
    let client = reqwest::blocking::Client::builder()
        .user_agent("Mozilla/5.0 (compatible; iphone-crate/0.1; +https://gitee.com/luzhihaoTestingLab/useful-cargo-packages)")
        .timeout(std::time::Duration::from_secs(10))
        .build()
        .map_err(|e| format!("client build error: {}", e))?;

    let mut model: Option<String> = None;
    let mut price: Option<u32> = None;
    let mut release: Option<String> = None;

    // 1) 从 Apple iPhone 页面推断型号与价格
    if let Ok(resp) = client.get("https://www.apple.com/iphone/").send() {
        if resp.status().is_success() {
            if let Ok(text) = resp.text() {
                // 提取最大编号的 iPhone 型号(例如 iPhone 17)
                let re_model = Regex::new(r"iPhone\s+(\d{2})").unwrap();
                let mut max_num: i32 = 0;
                for cap in re_model.captures_iter(&text) {
                    let n: i32 = cap[1].parse().unwrap_or(0);
                    if n > max_num { max_num = n; }
                }
                if max_num > 0 { model = Some(format!("iPhone {}", max_num)); }

                // 简单匹配 “From $XXX” 作为起售价(不保证地区与税费差异)
                let re_price = Regex::new(r"From\s*\$([0-9]{3,4})").unwrap();
                if let Some(cap) = re_price.captures(&text) {
                    price = cap[1].parse().ok();
                }
            }
        }
    }

    // 2) 从 Apple Newsroom 近似抓取发布日期(按新闻稿 time[datetime] 字段)
    if model.is_some() {
        if let Ok(resp) = client.get("https://www.apple.com/newsroom/").send() {
            if resp.status().is_success() {
                if let Ok(text) = resp.text() {
                    let re_date = Regex::new(r#"datetime=\"(\d{4}-\d{2}-\d{2})\""#).unwrap();
                    // 在整页中取第一个日期作为近似发布会日期;若能定位到包含 "iPhone" 的区域,则优先匹配该区域附近
                    if let Some(m) = &model {
                        if let Some(idx) = text.find(m) {
                            let start = idx.saturating_sub(600);
                            let end = std::cmp::min(text.len(), idx + 600);
                            let slice = &text[start..end];
                            if let Some(cap) = re_date.captures(slice) {
                                release = Some(cap[1].to_string());
                            }
                        }
                    }
                    if release.is_none() {
                        if let Some(cap) = re_date.captures(&text) {
                            release = Some(cap[1].to_string());
                        }
                    }
                }
            }
        }
    }

    // 有模型名则返回抓取结果,否则回退到静态值
    if let Some(m) = model {
        Ok(LatestIphone { model: m, price_usd: price, release_date: release })
    } else {
        Ok(latest())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn latest_static_values() {
        let li = latest();
        assert_eq!(li.model, "iPhone 17");
        assert_eq!(li.price_usd, Some(799));
        assert_eq!(li.release_date.as_deref(), Some("2025-09-09"));
    }
}