# 26.05.24

import re
import logging

from bs4 import BeautifulSoup

from VibraVid.utils.http_client import create_client, get_headers
from VibraVid.utils.js_beautifier import extract_setup, unpack


logger = logging.getLogger(__name__)


class VideoSource:
    def __init__(self, url: str) -> None:
        """
        Initializes the VideoSource object with default values.

        Attributes:
            - url (str): The URL of the video source.
        """
        self.headers = get_headers()
        self.url = url

    def make_request(self, url: str) -> str:
        """
        Make an HTTP GET request to the provided URL.

        Parameters:
            - url (str): The URL to make the request to.

        Returns:
            - str: The response content if successful, None otherwise.
        """
        try:
            response = create_client(headers=self.headers).get(url)
            if response.status_code >= 400:
                logger.error(f"Request failed with status code: {response.status_code}, to url: {url}")
                return None
            
            return response.text
        
        except Exception as e:
            logger.error(f"Request failed: {e}")
            return None
 
    def get_iframe(self, soup):
        """
        Extracts the source URL of the second iframe in the provided BeautifulSoup object.

        Parameters:
            - soup (BeautifulSoup): A BeautifulSoup object representing the parsed HTML.

        Returns:
            - str: The source URL of the second iframe, or None if not found.
        """
        iframes = soup.find_all("iframe")
        if iframes and len(iframes) > 1:
            return iframes[0].get("src") or iframes[0].get("data-src")
        
        return None

    def find_content(self, url):
        """
        Makes a request to the specified URL and parses the HTML content.

        Parameters:
            - url (str): The URL to fetch content from.

        Returns:
            - BeautifulSoup: A BeautifulSoup object representing the parsed HTML content, or None if the request fails.
        """
        content = self.make_request(url)
        if content:
            return BeautifulSoup(content, "html.parser")
        
        return None
        
    def get_result_node_js(self, soup):
        """
        Retrieves the JavaScript code from the provided BeautifulSoup object, unpacks it, and extracts the video source URL.

        Parameters:
            - soup (BeautifulSoup): A BeautifulSoup object representing the parsed HTML content.
        """
        for script in soup.find_all("script"):
            if "eval" in str(script):
                js = unpack(script.text)
                data = extract_setup(js)
                return data["sources"][0]["file"]
            
        return None

    def get_playlist(self) -> str:
        """
        Download a video from the provided URL.

        Returns:
            str: The URL of the downloaded video if successful, None otherwise.
        """
        try:
            html_content = self.make_request(self.url)
            if not html_content:
                logger.error("Failed to fetch HTML content.")
                return None

            # Find master playlist
            data_js = self.get_result_node_js(BeautifulSoup(html_content, "html.parser"))
            if data_js:
                return data_js
                    
            else:

                iframe_src = self.get_iframe(BeautifulSoup(html_content, "html.parser"))
                if not iframe_src:
                    logger.error("No iframe found.")
                    return None

                down_page_soup = self.find_content(iframe_src)
                if not down_page_soup:
                    logger.error("Failed to fetch down page content.")
                    return None

                pattern = r'data-link="(//supervideo[^"]+)"'
                match = re.search(pattern, str(down_page_soup))
                if not match:
                    logger.error("No player available for download.")
                    return None

                supervideo_url = "https:" + match.group(1)
                supervideo_soup = self.find_content(supervideo_url)
                if not supervideo_soup:
                    logger.error("Failed to fetch supervideo content.")
                    return None

                # Find master playlist
                data_js = self.get_result_node_js(supervideo_soup)
                if data_js:
                    return data_js
                else:
                    logger.error("No video source found in JavaScript.")
            
            return None

        except Exception as e:
            logger.error(f"An error occurred: {e}")
            return None
