use std::sync::OnceLock;

use regex::Regex;
use reqwest::Client;

use super::UnlockItem;

pub(super) async fn check_tiktok(client: &Client) -> UnlockItem {
    let trace_url = "https://www.tiktok.com/cdn-cgi/trace";

    let mut status = String::from("Failed");
    let mut region = None;

    if let Ok(response) = client.get(trace_url).send().await {
        let status_code = response.status().as_u16();
        if let Ok(body) = response.text().await {
            status = determine_status(status_code, &body).to_string();
            region = extract_region_from_body(&body);
        }
    }

    if (region.is_none() || status == "Failed")
        && let Ok(response) = client.get("https://www.tiktok.com/").send().await
    {
        let status_code = response.status().as_u16();
        if let Ok(body) = response.text().await {
            let fallback_status = determine_status(status_code, &body);
            let fallback_region = extract_region_from_body(&body);

            if status != "No" {
                status = fallback_status.to_string();
            }

            if region.is_none() {
                region = fallback_region;
            }
        }
    }

    UnlockItem::checked("TikTok", status, region)
}

fn determine_status(status: u16, body: &str) -> &'static str {
    if status == 403 || status == 451 {
        return "No";
    }

    if !(200..300).contains(&status) {
        return "Failed";
    }

    let body_lower = body.to_lowercase();
    if body_lower.contains("access denied")
        || body_lower.contains("not available in your region")
        || body_lower.contains("tiktok is not available")
    {
        return "No";
    }

    "Yes"
}

fn extract_region_from_body(body: &str) -> Option<String> {
    static REGION_REGEX: OnceLock<Option<Regex>> = OnceLock::new();
    let regex = REGION_REGEX
        .get_or_init(|| Regex::new(r#""region"\s*:\s*"([a-zA-Z-]+)""#).ok())
        .as_ref()?;

    if let Some(caps) = regex.captures(body)
        && let Some(matched) = caps.get(1)
    {
        let raw = matched.as_str();
        let country_code = raw.split('-').next().unwrap_or(raw).to_uppercase();
        if !country_code.is_empty() {
            return Some(UnlockItem::region_label(&country_code));
        }
    }

    None
}
