use super::error::Error;
use super::ext::VideoThumbnailExtractorExt;
use async_trait::async_trait;
use kuchikikiki::{NodeRef, traits::*};
use reqwest::{Client, Response};

#[derive(Debug, Clone)]
pub struct PeertubeThumbnailExtractor;

impl PeertubeThumbnailExtractor {
    fn check_content_type(response: &Response) -> Result<bool, Error> {
        if !response.status().is_success() {
            return Err(Error::Parse);
        }

        if let Some(content_type) = response.headers().get(reqwest::header::CONTENT_TYPE)
            && let Ok(content_type) = content_type.to_str()
            && content_type.contains("text/html")
        {
            return Ok(true);
        }

        Ok(false)
    }

    fn get_meta_content(dom: &NodeRef, property: &str) -> Option<String> {
        tracing::trace!(property, "get metadata with property");
        let meta_nodes = dom.select(&format!("meta[property='{property}']")).ok()?;
        let meta_node = meta_nodes.into_iter().next()?;
        meta_node.attributes.borrow().get("content").map(|content| {
            tracing::trace!(property, content, "metadata");
            content.to_string()
        })
    }
}

#[async_trait]
impl VideoThumbnailExtractorExt for PeertubeThumbnailExtractor {
    fn matches_url(&self, video_url: &str) -> bool {
        video_url.contains("/w/")
    }

    async fn get_thumbnail_url(&self, video_url: &str, client: &Client) -> Result<String, Error> {
        let response = client.get(video_url).send().await?;

        if !Self::check_content_type(&response)? {
            return Err(Error::Parse);
        }
        let html = response.text().await?;

        tracing::trace!(html);

        let dom = kuchikikiki::parse_html().one(html);

        let Some(plattform) = Self::get_meta_content(&dom, "og:platform") else {
            return Err(Error::Parse);
        };

        if plattform.as_str() != "PeerTube" {
            return Err(Error::Parse);
        }

        Self::get_meta_content(&dom, "twitter:image").ok_or(Error::Parse)
    }
}
