use ntex::web;
use serde_json::Value;
use wreq::Version;

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

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

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

    fn extract_playlist(text: &str) -> Option<&str> {
        text.split("window.playlist = ").nth(1)?.split(';').next()
    }

    fn source_score(source: &Value) -> (u8, u32) {
        let file = source["file"].as_str().unwrap_or_default();
        let label = source["label"].as_str().unwrap_or_default();
        let is_hls = u8::from(file.contains(".m3u8"));
        let quality = label
            .chars()
            .filter(|c| c.is_ascii_digit())
            .collect::<String>()
            .parse::<u32>()
            .unwrap_or(0);

        (is_hls, quality)
    }

    fn select_best_source(playlist: &str) -> Option<String> {
        let json: Value = serde_json::from_str(playlist).ok()?;
        let sources = json["sources"].as_array()?;

        sources
            .iter()
            .filter(|source| {
                source["file"]
                    .as_str()
                    .map(|file| !file.is_empty())
                    .unwrap_or(false)
            })
            .max_by_key(|source| Self::source_score(source))
            .and_then(|source| source["file"].as_str())
            .map(str::to_string)
    }

    pub async fn get_video_url(
        &self,
        url: String,
        requester: web::types::State<Requester>,
    ) -> String {
        let mut requester = requester.get_ref().clone();
        let url = if url.starts_with("http://") || url.starts_with("https://") {
            url
        } else {
            format!("https://{}", url.trim_start_matches('/'))
        };
        let text = requester
            .get(&url, Some(Version::HTTP_2))
            .await
            .unwrap_or_default();
        if text.is_empty() {
            return String::new();
        }

        let Some(playlist) = Self::extract_playlist(&text) else {
            return String::new();
        };

        Self::select_best_source(playlist).unwrap_or_default()
    }
}

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

    #[test]
    fn extracts_playlist_from_page() {
        let html = r#"
            <script>
                window.playlist = {"sources":[{"file":"https://cdn.example/360.mp4","label":"360p"}]};
            </script>
        "#;

        assert_eq!(
            NoodlemagazineProxy::extract_playlist(html),
            Some(r#"{"sources":[{"file":"https://cdn.example/360.mp4","label":"360p"}]}"#)
        );
    }

    #[test]
    fn prefers_hls_then_highest_quality() {
        let playlist = r#"{
            "sources": [
                {"file":"https://cdn.example/360.mp4","label":"360p"},
                {"file":"https://cdn.example/720.mp4","label":"720p"},
                {"file":"https://cdn.example/master.m3u8","label":"1080p"}
            ]
        }"#;

        assert_eq!(
            NoodlemagazineProxy::select_best_source(playlist).as_deref(),
            Some("https://cdn.example/master.m3u8")
        );
    }
}
