"""
Web Content Extractor Module

Provides functionalities to fetch web content using headless Chrome,
sanitize HTML, and save results with comprehensive logging and error handling.
"""

import logging
import os
import time
import random
import string
from typing import Optional

from lxml.html.clean import Cleaner
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)

# Configuration constants
DEFAULT_CHROME_PATH = "run/webdriver/chrome"
DEFAULT_WEB_DRIVER_PATH = "run/webdriver/chromedriver"
DEFAULT_WAIT_TIME = 10
DEFAULT_OUTPUT_DIR = "run/tmp"

CHROME_OPTIONS = [
    "--headless",
    "--no-sandbox",
    "--disable-dev-shm-usage",
    "--disable-extensions",
    "--disable-gpu",
    "window-size=1920,1080"
]

CLEANER_CONFIG = {
    'page_structure': True,
    'meta': True,
    'embedded': True,
    'links': True,
    'style': True,
    'processing_instructions': True,
    'inline_style': True,
    'scripts': True,
    'javascript': True,
    'comments': True,
    'frames': True,
    'forms': True,
    'annoying_tags': True,
    'remove_unknown_tags': True,
    'safe_attrs_only': True,
    'safe_attrs': frozenset(['src', 'color', 'href', 'title', 'class', 'name', 'id']),
    'remove_tags': ('span', 'font', 'div')
}

ALLOWED_TAGS = {
    'img': ['src', 'alt', 'width', 'height'],
    'a': ['href', 'title'],
    'video': ['src', 'controls', 'width', 'height'],
    'source': ['src', 'type']
}

UNWANTED_TAGS = [
    'script', 'style', 'nav', 'footer', 'header', 'aside',
    'form', 'iframe', 'noscript', 'svg', 'canvas', 'applet',
    'object', 'embed'
]


def configure_chrome_driver() -> webdriver.Chrome:
    """Configure and return a Chrome WebDriver instance."""
    try:
        chrome_options = Options()
        for option in CHROME_OPTIONS:
            chrome_options.add_argument(option)

        chrome_path = os.path.join(
            DEFAULT_CHROME_PATH, 'chrome-linux64', 'chrome'
        )
        chrome_options.binary_location = chrome_path

        driver_path = os.path.join(
            DEFAULT_WEB_DRIVER_PATH, 'chromedriver'
        )
        chrome_service = Service(driver_path)

        logger.info("Initializing Chrome WebDriver")
        return webdriver.Chrome(
            service=chrome_service,
            options=chrome_options
        )
    except Exception as e:
        logger.error("Chrome driver configuration failed")
        raise RuntimeError("WebDriver initialization failed") from e


def extract_html_with_chromedriver(
    url: str,
    wait_time: int = DEFAULT_WAIT_TIME
) -> Optional[str]:
    """
    Extract HTML content from a URL using headless Chrome.

    Args:
        url: Target URL to scrape
        wait_time: Maximum wait time for page load (seconds)

    Returns:
        str: Raw HTML content or None if extraction fails
    """
    driver = None
    try:
        driver = configure_chrome_driver()
        logger.info(f"Fetching URL: {url}")
        
        driver.get(url)
        WebDriverWait(driver, wait_time).until(
            EC.presence_of_element_located((By.TAG_NAME, 'body'))
        )
        
        logger.debug("Page load completed successfully")
        return driver.page_source

    except Exception as e:
        logger.error(f"Failed to extract HTML: {str(e)}")
        return None
    finally:
        if driver:
            logger.debug("Closing WebDriver instance")
            driver.quit()


def sanitize_html(dirty_html: str) -> str:
    """
    Sanitize HTML content using lxml cleaner.

    Args:
        dirty_html: Raw HTML input

    Returns:
        str: Sanitized HTML output
    """
    try:
        logger.info("Sanitizing HTML content")
        cleaner = Cleaner(**CLEANER_CONFIG)
        return cleaner.clean_html(dirty_html)
    except Exception as e:
        logger.error(f"HTML sanitization failed: {str(e)}")
        raise


def extract_content(html_content: str) -> Optional[str]:
    """
    Extract and clean main content from HTML.

    Args:
        html_content: Raw HTML input

    Returns:
        str: Cleaned HTML content or None if processing fails
    """
    try:
        if not html_content:
            logger.warning("Empty HTML content received")
            return None

        logger.info("Processing HTML content")
        soup = BeautifulSoup(html_content, "html.parser")

        # Remove unwanted tags
        for tag in soup.find_all(UNWANTED_TAGS):
            tag.decompose()

        # Clean tag attributes
        for tag in soup.find_all():
            allowed = ALLOWED_TAGS.get(tag.name, [])
            attrs = list(tag.attrs.keys())
            for attr in attrs:
                if attr not in allowed:
                    del tag[attr]

        # Remove empty tags
        for tag in soup.find_all():
            if not tag.get_text(strip=True):
                tag.decompose()

        return str(soup)
    except Exception as e:
        logger.error(f"Content extraction failed: {str(e)}")
        return None


def save_html_to_file(
    html_content: str,
    output_dir: str = DEFAULT_OUTPUT_DIR
) -> Optional[str]:
    """
    Save HTML content to timestamped file.

    Args:
        html_content: Content to save
        output_dir: Target directory path

    Returns:
        str: Path to saved file or None if save fails
    """
    try:
        os.makedirs(output_dir, exist_ok=True)
        timestamp = time.strftime("%Y%m%d%H%M%S")
        rand_str = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
        filename = f"output_{timestamp}_{rand_str}.html"
        filepath = os.path.join(output_dir, filename)

        logger.info(f"Saving output to: {filepath}")
        with open(filepath, "w", encoding="utf-8") as f:
            f.write(html_content)

        return filepath
    except Exception as e:
        logger.error(f"File save failed: {str(e)}")
        return None


def get_content_from_url(url: str) -> Optional[str]:
    """
    Main pipeline: Fetch URL -> Extract Content -> Sanitize HTML

    Args:
        url: Target URL to process

    Returns:
        str: Processed HTML content or None if any step fails
    """
    try:
        raw_html = extract_html_with_chromedriver(url)
        if not raw_html:
            return None

        sanitized = sanitize_html(raw_html)
        return extract_content(sanitized)
    except Exception as e:
        logger.error(f"Processing pipeline failed: {str(e)}")
        return None


if __name__ == "__main__":
    target_url = "https://www.cncf.io/blog/2025/01/22/kubernetes-in-2025-are-you-ready-for-these-top-5-trends-and-predictions/"
    if (result := get_content_from_url(target_url)) is not None:
        file_path = save_html_to_file(result)
        if file_path:
            logger.info(f"Successfully saved output to: {file_path}")
        else:
            logger.error("Failed to save output file")
    else:
        logger.error("Content extraction failed for target URL")