"""
WebDriver Manager for Cognitive Prism Automation Tests
"""
import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.edge.options import Options as EdgeOptions
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from config.config import (
    BROWSER, HEADLESS, IMPLICIT_WAIT, PAGE_LOAD_TIMEOUT, DOWNLOAD_DIR
)


class DriverManager:
    """Manages WebDriver instances"""
    
    @staticmethod
    def get_driver(headless=None):
        """
        Creates and returns a WebDriver instance based on configuration
        
        Args:
            headless: Force headless mode (None = use config, True = headless, False = visible)
        
        Returns:
            WebDriver: Configured WebDriver instance
        """
        if BROWSER == "chrome":
            return DriverManager._get_chrome_driver(headless=headless)
        elif BROWSER == "firefox":
            return DriverManager._get_firefox_driver(headless=headless)
        elif BROWSER == "edge":
            return DriverManager._get_edge_driver(headless=headless)
        else:
            raise ValueError(f"Unsupported browser: {BROWSER}")
    
    @staticmethod
    def _get_chrome_driver(headless=None):
        """
        Creates and returns Chrome WebDriver
        
        Args:
            headless: Force headless mode (None = use config, True = headless, False = visible)
        """
        options = Options()
        
        # Determine headless mode
        use_headless = headless if headless is not None else HEADLESS
        
        if use_headless:
            options.add_argument("--headless")
            options.add_argument("--disable-gpu")
        
        # Performance options (important for load testing)
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        options.add_argument("--window-size=1920,1080")
        # Additional performance optimizations for load testing
        if use_headless:
            options.add_argument("--disable-extensions")
            options.add_argument("--disable-plugins")
            # Note: --disable-images might break some tests, so we'll skip it for now
        
        # Download preferences
        prefs = {
            "download.default_directory": DOWNLOAD_DIR,
            "download.prompt_for_download": False,
            "download.directory_upgrade": True,
            "safebrowsing.enabled": True
        }
        options.add_experimental_option("prefs", prefs)
        
        # Get ChromeDriver path - webdriver-manager may return directory or file path
        driver_path = ChromeDriverManager().install()
        original_path = driver_path
        
        # Handle case where webdriver-manager returns a file path instead of directory
        if os.path.isfile(driver_path):
            # If it's a file, check if it's the actual executable
            file_size = os.path.getsize(driver_path)
            if file_size > 10000000:  # > 10MB is definitely the executable
                # This is the actual chromedriver executable
                pass  # Use it as-is
            else:
                # It's not the executable, search in parent directory
                driver_path = os.path.dirname(driver_path)
                original_path = driver_path
        
        # Ensure we have the actual chromedriver executable, not a directory or text file
        if os.path.isdir(driver_path):
            # Strategy: Search for files named exactly "chromedriver" (no extension, no prefix)
            # and pick the largest one (executable is 10-20MB, text files are < 1MB)
            candidate_files = []
            
            # Search directory tree for files named exactly "chromedriver"
            for root, dirs, files in os.walk(original_path):
                for file in files:
                    # CRITICAL: File must be named EXACTLY "chromedriver" with no extension
                    # This excludes "THIRD_PARTY_NOTICES.chromedriver", "LICENSE.chromedriver", etc.
                    # Use strict equality check - file name must be exactly "chromedriver"
                    if file == "chromedriver" and len(file) == 12:  # "chromedriver" is 12 chars
                        full_path = os.path.join(root, file)
                        if os.path.isfile(full_path):
                            file_size = os.path.getsize(full_path)
                            # Only consider files > 1MB (executable size threshold)
                            if file_size > 1000000:
                                candidate_files.append((full_path, file_size))
            
            # If we found candidate files, pick the largest one
            if candidate_files:
                # Sort by size (largest first)
                candidate_files.sort(key=lambda x: x[1], reverse=True)
                # Pick the largest file - this should be the actual executable (10-20MB)
                driver_path = candidate_files[0][0]
                file_size = candidate_files[0][1]
                
                # Validate it's large enough (should be > 10MB for ChromeDriver)
                if file_size < 10000000:  # Less than 10MB is suspicious
                    # But allow if it's at least > 1MB and we have no better option
                    if file_size < 1000000:
                        raise FileNotFoundError(
                            f"Found chromedriver file but size ({file_size} bytes) is too small.\n"
                            f"Expected > 1MB. Path: {driver_path}\n"
                            f"Found {len(candidate_files)} candidate file(s)."
                        )
            else:
                # No candidate files found
                raise FileNotFoundError(
                    f"ChromeDriver executable not found in {original_path}.\n"
                    f"Searched for files named exactly 'chromedriver' with size > 1MB."
                )
        
        # Final validation - ensure it's a file
        if not os.path.isfile(driver_path):
            raise FileNotFoundError(
                f"ChromeDriver executable not found. Searched in: {original_path}\n"
                f"Please ensure ChromeDriver is properly installed."
            )
        
        # Verify it's the actual executable (large file, not text file)
        file_size = os.path.getsize(driver_path)
        if file_size < 1000000:  # Less than 1MB is likely not the executable
            raise FileNotFoundError(
                f"Found chromedriver file but it appears to be a text file (size: {file_size} bytes).\n"
                f"Expected executable size > 1MB. Path: {driver_path}\n"
                f"Please check the ChromeDriver installation."
            )
        
        # Make it executable if needed
        if not os.access(driver_path, os.X_OK):
            os.chmod(driver_path, 0o755)
            if not os.access(driver_path, os.X_OK):
                raise PermissionError(
                    f"ChromeDriver at {driver_path} is not executable and could not be made executable."
                )
        
        service = Service(driver_path)
        driver = webdriver.Chrome(service=service, options=options)
        
        # Set timeouts
        driver.implicitly_wait(IMPLICIT_WAIT)
        driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
        
        return driver
    
    @staticmethod
    def _get_firefox_driver(headless=None):
        """
        Creates and returns Firefox WebDriver
        
        Args:
            headless: Force headless mode (None = use config, True = headless, False = visible)
        """
        options = FirefoxOptions()
        
        # Determine headless mode
        use_headless = headless if headless is not None else HEADLESS
        
        if use_headless:
            options.add_argument("--headless")
        
        # Download preferences
        options.set_preference("browser.download.folderList", 2)
        options.set_preference("browser.download.dir", DOWNLOAD_DIR)
        options.set_preference("browser.download.useDownloadDir", True)
        options.set_preference("browser.helperApps.neverAsk.saveToDisk", 
                              "application/json,text/csv")
        
        service = FirefoxService(GeckoDriverManager().install())
        driver = webdriver.Firefox(service=service, options=options)
        
        # Set timeouts
        driver.implicitly_wait(IMPLICIT_WAIT)
        driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
        
        return driver
    
    @staticmethod
    def _get_edge_driver(headless=None):
        """
        Creates and returns Edge WebDriver
        
        Args:
            headless: Force headless mode (None = use config, True = headless, False = visible)
        """
        options = EdgeOptions()
        
        # Determine headless mode
        use_headless = headless if headless is not None else HEADLESS
        
        if use_headless:
            options.add_argument("--headless")
        
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        options.add_argument("--window-size=1920,1080")
        
        # Download preferences
        prefs = {
            "download.default_directory": DOWNLOAD_DIR,
            "download.prompt_for_download": False,
            "download.directory_upgrade": True
        }
        options.add_experimental_option("prefs", prefs)
        
        service = EdgeService(EdgeChromiumDriverManager().install())
        driver = webdriver.Edge(service=service, options=options)
        
        # Set timeouts
        driver.implicitly_wait(IMPLICIT_WAIT)
        driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
        
        return driver
    
    @staticmethod
    def quit_driver(driver):
        """Quits the WebDriver instance"""
        if driver:
            driver.quit()

