use std::sync::Arc;

use ntex::web;
use url::Url;
use wreq::cookie::Jar;
use wreq::redirect::Policy;
use wreq_util::Emulation;

use crate::util::{dean_edwards, requester::Requester};

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

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

    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("lulustream.com/")
            || endpoint.starts_with("www.lulustream.com/")
            || endpoint.starts_with("luluvid.com/")
        {
            format!("https://{endpoint}")
        } else {
            format!("https://lulustream.com/{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 == "lulustream.com" || host == "www.lulustream.com" || host == "luluvid.com")
            && !parsed.path().is_empty()
            && parsed.path() != "/"
    }

    // Chrome120 emulation bypasses Cloudflare on luluvid.com (Firefox136 gets blocked).
    fn build_chrome_client() -> Option<wreq::Client> {
        let jar = Arc::new(Jar::default());
        wreq::Client::builder()
            .cert_verification(false)
            .emulation(Emulation::Chrome120)
            .cookie_provider(jar)
            .redirect(Policy::default())
            .build()
            .ok()
    }

    fn extract_media_url(html: &str) -> Option<String> {
        // Fast path: file URL present in plain text (no packing)
        if html.contains("[{file:\"") {
            let url = html
                .split("[{file:\"")
                .nth(1)
                .and_then(|s| s.split('"').next())?
                .to_string();
            if !url.is_empty() {
                return Some(url);
            }
        }

        // Unpack the Dean Edwards p,a,c,k,e,d script that embeds the player config.
        // The packed payload encodes the jwplayer setup call; after decoding it contains
        // `sources:[{file:"https://cdn*.cdn-tnmr.org/hls2/.../master.m3u8?..."}]`.
        let packed = html
            .split("<script type='text/javascript'>")
            .nth(1)
            .and_then(|t| t.split("</script>").next())?;

        let unpacked = dean_edwards::unpack(packed).ok()?;

        unpacked
            .split("[{file:\"")
            .nth(1)
            .and_then(|s| s.split('"').next())
            .map(|s| s.to_string())
            .filter(|s| !s.is_empty())
    }

    async fn try_chrome_extraction(embed_url: &str) -> Option<String> {
        let client = Self::build_chrome_client()?;
        let response = client.get(embed_url).send().await.ok()?;
        if !response.status().is_success() {
            return None;
        }
        let html = response.text().await.ok()?;
        Self::extract_media_url(&html)
    }
}

impl crate::proxies::Proxy for LulustreamProxy {
    async fn get_video_url(&self, url: String, requester: web::types::State<Requester>) -> String {
        let Some((_detail_url, video_id)) = Self::normalize_detail_request(&url) else {
            return String::new();
        };

        let embed_url = format!("https://luluvid.com/e/{video_id}");

        // Chrome120 emulation bypasses Cloudflare; try it first.
        if let Some(media_url) = Self::try_chrome_extraction(&embed_url).await {
            return media_url;
        }

        // Fallback: standard requester (Firefox136 + optional FlareSolverr).
        let mut requester = requester.get_ref().clone();
        let html = requester.get(&embed_url, None).await.unwrap_or_default();
        Self::extract_media_url(&html).unwrap_or_default()
    }
}

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

    #[test]
    fn normalizes_detail_request_with_full_url() {
        let (url, video_id) =
            LulustreamProxy::normalize_detail_request("https://lulustream.com/d/s484n23k8opy")
                .expect("detail request should parse");
        assert_eq!(url, "https://lulustream.com/d/s484n23k8opy");
        assert_eq!(video_id, "s484n23k8opy");
    }

    #[test]
    fn normalizes_detail_request_with_path_only() {
        let (url, video_id) = LulustreamProxy::normalize_detail_request("d/s484n23k8opy")
            .expect("detail request should parse");
        assert_eq!(url, "https://lulustream.com/d/s484n23k8opy");
        assert_eq!(video_id, "s484n23k8opy");
    }

    #[test]
    fn normalizes_luluvid_url() {
        let (url, video_id) =
            LulustreamProxy::normalize_detail_request("https://luluvid.com/e/s484n23k8opy")
                .expect("detail request should parse");
        assert_eq!(url, "https://luluvid.com/e/s484n23k8opy");
        assert_eq!(video_id, "s484n23k8opy");
    }

    #[test]
    fn extracts_media_url_from_plain_html() {
        let html = r#"[{file:"https://cdn1007.cdn-tnmr.org/hls2/02/02723/abc_h/master.m3u8?t=TOKEN&s=12345&e=28800&f=999&i=0.3&sp=0"}]"#;
        assert_eq!(
            LulustreamProxy::extract_media_url(html).as_deref(),
            Some("https://cdn1007.cdn-tnmr.org/hls2/02/02723/abc_h/master.m3u8?t=TOKEN&s=12345&e=28800&f=999&i=0.3&sp=0")
        );
    }

    #[test]
    fn extracts_media_url_from_packed_script() {
        // Minimal valid packed script that decodes to a jwplayer sources array.
        // Original: jwplayer("vplayer").setup({sources:[{file:"https://cdn.example.com/video.m3u8"}]})
        // We fake it with a trivial packer (base 10, a few words).
        let fake_packed = r#"eval(function(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\b'+c.toString(a)+'\b','g'),k[c]);return p}('0("[{1:\"https://cdn.example.com/video.m3u8\"}]")',10,2,'sources|file'.split('|'),0,{}))"#;
        let html = format!("<script type='text/javascript'>{fake_packed}</script>");
        let url = LulustreamProxy::extract_media_url(&html);
        assert!(url.is_some(), "should extract a URL from packed script");
    }
}
