use ntex::web;
use url::Url;
use serde_json::json;

use crate::util::requester::Requester;

#[derive(Debug, Clone)]
pub struct VidaraProxy {}

impl VidaraProxy {
    pub fn new() -> Self {
        VidaraProxy {}
    }

    fn normalize_detail_request(endpoint: &str) -> Option<(String, String)> {
        let endpoint = endpoint.trim().trim_start_matches('/');
        if endpoint.is_empty() {
            return None;
        }

        let detail_url = if endpoint.starts_with("http://") || endpoint.starts_with("https://") {
            endpoint.to_string()
        } else if endpoint.starts_with("vidara.so/") || endpoint.starts_with("www.vidara.so/")
        {
            format!("https://{endpoint}")
        } else {
            format!("https://vidara.so/{endpoint}")
        };

        if !Self::is_allowed_detail_url(&detail_url) {
            return None;
        }

        let parsed = Url::parse(&detail_url).ok()?;
        let video_id = parsed.path_segments()?
            .last()
            .map(ToOwned::to_owned)?;

        Some((detail_url, video_id))
    }

    fn is_allowed_detail_url(url: &str) -> bool {
        let Some(parsed) = Url::parse(url).ok() else {
            return false;
        };
        if parsed.scheme() != "https" {
            return false;
        }
        let Some(host) = parsed.host_str() else {
            return false;
        };
        (host == "vidara.so" || host == "www.vidara.so")
            && (parsed.path().starts_with("/v/")||parsed.path().starts_with("/e/"))
    }

    pub async fn get_video_url(
        &self,
        url: String,
        requester: web::types::State<Requester>,
    ) -> String {
        let mut requester = requester.get_ref().clone();
        let Some((detail_url, video_id)) = Self::normalize_detail_request(&url) else {
            println!("VidaraProxy: Invalid detail URL: {url}");
            return String::new();
        };

        let body = json!({
            "filecode": video_id,
            "device": "web"
        });
        // println!("VidaraProxy: Requesting streaming URL for {detail_url} with body: {body}");
        let response = requester
            .post_json(
                "https://vidara.so/api/stream",
                &body,
                vec![
                    ("Referer".to_string(), detail_url.clone())
                    ],
            )
            .await;

        // println!("VidaraProxy: Requested streaming URL for {detail_url}, got response: {:?}", response);

        let Ok(response) = response else {
            return String::new();
        };
        let Ok(response_text) = response.text().await else {
            return String::new();
        };

        // println!("VidaraProxy: Response text for {detail_url}: {response_text}");

        let Ok(json): Result<serde_json::Value, _> = serde_json::from_str(&response_text) else {
            return String::new();
        };

        json["streaming_url"]
            .as_str()
            .map(ToOwned::to_owned)
            .unwrap_or_default()
    }
}

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

    #[test]
    fn normalizes_detail_request_with_full_url() {
        let (url, video_id) =
            VidaraProxy::normalize_detail_request("https://vidara.so/v/eJ9O4QqG1Ln2")
                .expect("detail request should parse");
        assert_eq!(url, "https://vidara.so/v/eJ9O4QqG1Ln2");
        assert_eq!(video_id, "eJ9O4QqG1Ln2");
    }

    #[test]
    fn normalizes_detail_request_with_path_only() {
        let (url, video_id) = VidaraProxy::normalize_detail_request("video/1000/demo")
            .expect("detail request should parse");
        assert_eq!(url, "https://vidara.so/video/1000/demo");
        assert_eq!(video_id, "1000");
    }
}
