use different browswer like 
import logging
import os
import sys
import time
import random
from dataclasses import dataclass, field
from typing import List, Optional

from selenium import webdriver
from selenium.common.exceptions import (
    TimeoutException,
    WebDriverException,
    NoSuchElementException,
    StaleElementReferenceException,
)
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.file_detector import LocalFileDetector
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)],
)

@dataclass
class SearchResult:
    query: str
    urls: List[str] = field(default_factory=list)
    image_urls: List[str] = field(default_factory=list)
    video_urls: List[str] = field(default_factory=list)

class AdvancedSearchTool:
    """A tool to perform advanced searches and handle file uploads/downloads."""

    def __init__(
        self,
        headless: bool = True,
        wait_time: int = 30,  # Increased wait_time
        download_dir: Optional[str] = None,
    ) -> None:
        """
        Initialize the AdvancedSearchTool.

        Args:
            headless (bool): Run browser in headless mode.
            wait_time (int): Maximum wait time for page elements to load.
            download_dir (Optional[str]): Directory to save downloaded files.
        """
        self.headless = headless
        self.wait_time = wait_time
        self.download_dir = download_dir or os.path.join(os.getcwd(), "downloads")
        os.makedirs(self.download_dir, exist_ok=True)
        self.driver = self._init_webdriver()

    def _init_webdriver(self) -> webdriver.Chrome:
        """Initialize the Selenium WebDriver with specified options."""
        options = Options()
        if self.headless:
            options.add_argument("--headless")
        options.add_argument("--disable-gpu")
        options.add_argument("--no-sandbox")
        options.add_argument("--window-size=1920,1080")
        options.add_argument(
            "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/89.0.4389.82 Safari/537.36"
        )
        options.add_experimental_option("excludeSwitches", ["enable-automation"])
        options.add_experimental_option('useAutomationExtension', False)
        prefs = {
            "download.default_directory": self.download_dir,
            "download.prompt_for_download": False,
            "download.directory_upgrade": True,
            "safebrowsing.enabled": True,
        }
        options.add_experimental_option("prefs", prefs)

        try:
            service = ChromeService(ChromeDriverManager().install())
            driver = webdriver.Chrome(
                service=service,
                options=options
            )
            # Evade detection
            driver.execute_cdp_cmd(
                "Page.addScriptToEvaluateOnNewDocument",
                {
                    "source": """
                    Object.defineProperty(navigator, 'webdriver', {
                        get: () => undefined
                    });
                    window.navigator.chrome = {
                        runtime: {}
                    };
                    Object.defineProperty(navigator, 'languages', {
                        get: () => ['en-US', 'en']
                    });
                    Object.defineProperty(navigator, 'plugins', {
                        get: () => [1, 2, 3, 4, 5],
                    });
                    """
                },
            )
            # Inject wait time to avoid detection
            driver.execute_script("Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5], });")
            driver.implicitly_wait(10)  # Implicit wait

            logging.info("WebDriver initialized successfully.")
            return driver
        except WebDriverException as e:
            logging.error(f"Error initializing WebDriver: {e}")
            raise

    def robust_wait(self, by, value):
        """A robust wait method that retries on certain exceptions."""
        for attempt in range(3):
            try:
                return WebDriverWait(self.driver, self.wait_time).until(
                    EC.presence_of_element_located((by, value))
                )
            except (TimeoutException, StaleElementReferenceException) as e:
                logging.warning(f"Attempt {attempt + 1}: Element not found: {e}")
                time.sleep(2)  # Wait before retrying
        raise TimeoutException(f"Element {value} not found after retries.")

    def search(self, query: str) -> Optional[SearchResult]:
        """
        Perform a search for the given query and retrieve related URLs, images, and videos.

        Args:
            query (str): The search query.

        Returns:
            Optional[SearchResult]: The search results containing URLs, images, and videos.
        """
        result = SearchResult(query=query)
        try:
            encoded_query = query.replace(' ', '+')

            # General Web Search
            general_search_url = f"https://www.google.com/search?q={encoded_query}"
            self.driver.get(general_search_url)
            logging.info(f"Navigated to {general_search_url}")
            time.sleep(random.uniform(2, 4))  # Mimic human behavior

            # Invoke robust_wait
            self.robust_wait(By.CSS_SELECTOR, "div.yuRUbf > a")

            # Extract general URLs using Selenium directly
            links = self.driver.find_elements(By.CSS_SELECTOR, "div.yuRUbf > a")
            for link in links:
                href = link.get_attribute("href")
                if href:
                    result.urls.append(href)
            logging.info(f"Found {len(result.urls)} general URLs.")

            # Image Search
            image_search_url = f"https://www.google.com/search?q={encoded_query}&tbm=isch"
            self.driver.get(image_search_url)
            logging.info(f"Navigated to {image_search_url}")
            time.sleep(random.uniform(2, 4))  # Mimic human behavior

            self.robust_wait(By.CSS_SELECTOR, "img")

            # Extract image URLs using Selenium directly
            images = self.driver.find_elements(By.CSS_SELECTOR, "img")
            for img in images:
                src = img.get_attribute("src") or img.get_attribute("data-src")
                if src and src.startswith("http"):
                    result.image_urls.append(src)
            logging.info(f"Found {len(result.image_urls)} images.")

            # Video Search
            video_search_url = f"https://www.google.com/search?q={encoded_query}&tbm=vid"
            self.driver.get(video_search_url)
            logging.info(f"Navigated to {video_search_url}")
            time.sleep(random.uniform(2, 4))  # Mimic human behavior

            self.robust_wait(By.CSS_SELECTOR, "a[href*='/url?q=']")

            # Extract video URLs using Selenium directly
            videos = self.driver.find_elements(By.CSS_SELECTOR, "a[href*='/url?q=']")
            for a in videos:
                href = a.get_attribute("href")
                if "url?q=" in href:
                    clean_url = href.split("url?q=")[1].split("&")[0]
                    result.video_urls.append(clean_url)
            logging.info(f"Found {len(result.video_urls)} videos.")

            return result

        except TimeoutException as e:
            logging.error(f"Timeout occurred: {e}")
            self.driver.save_screenshot("timeout_error.png")
            logging.info("Saved screenshot as timeout_error.png")
        except NoSuchElementException as e:
            logging.error(f"Element not found: {e}")
            self.driver.save_screenshot("no_such_element.png")
            logging.info("Saved screenshot as no_such_element.png")
        except Exception as e:
            logging.error(f"An unexpected error occurred: {e}")
            self.driver.save_screenshot("unexpected_error.png")
            logging.info("Saved screenshot as unexpected_error.png")

        return None

    def upload_file(self, upload_url: str, file_path: str) -> bool:
        """
        Upload a file to the specified URL.

        Args:
            upload_url (str): The URL of the upload page.
            file_path (str): The path to the file to upload.

        Returns:
            bool: True if upload was successful, False otherwise.
        """
        try:
            self.driver.get(upload_url)
            logging.info(f"Navigated to {upload_url}")
            time.sleep(random.uniform(2, 4))  # Mimic human behavior

            # Wait until the file input is present
            self.robust_wait(By.CSS_SELECTOR, "input[type='file']")

            # Set file detector for remote if necessary
            if hasattr(self.driver, 'file_detector'):
                self.driver.file_detector = LocalFileDetector()

            # Find the file input and upload the file
            file_input = self.driver.find_element(By.CSS_SELECTOR, "input[type='file']")
            file_input.send_keys(os.path.abspath(file_path))
            logging.info(f"Uploaded file: {file_path}")
            time.sleep(random.uniform(1, 2))  # Wait after upload

            # Submit the form
            submit_button = self.driver.find_element(By.ID, "file-submit")
            submit_button.click()
            logging.info("Submitted the upload form.")
            time.sleep(random.uniform(2, 4))  # Wait for submission

            # Wait for the upload to complete
            self.robust_wait(By.ID, "uploaded-files")

            uploaded_file = self.driver.find_element(By.ID, "uploaded-files").text
            if os.path.basename(file_path) == uploaded_file:
                logging.info("File uploaded successfully.")
                return True
            else:
                logging.error("Uploaded file name does not match.")
                return False

        except Exception as e:
            logging.error(f"Error during file upload: {e}")
            self.driver.save_screenshot("upload_error.png")
            logging.info("Saved screenshot as upload_error.png")
            return False

    def download_file(self, download_url: str, file_name: str, timeout: int = 30) -> bool:
        """
        Download a file from the specified URL.

        Args:
            download_url (str): The URL to download the file from.
            file_name (str): The expected name of the downloaded file.
            timeout (int): Maximum time to wait for the download to complete.

        Returns:
            bool: True if download was successful, False otherwise.
        """
        try:
            self.driver.get(download_url)
            logging.info(f"Navigated to {download_url}")
            time.sleep(random.uniform(2, 4))  # Mimic human behavior

            # Initiate the download by clicking the download link/button
            download_element = self.driver.find_element(By.LINK_TEXT, file_name)
            download_element.click()
            logging.info(f"Initiated download for {file_name}")

            # Wait for the file to appear in the download directory
            download_path = os.path.join(self.download_dir, file_name)
            logging.info(f"Waiting for {download_path} to appear...")

            for _ in range(timeout):
                if os.path.exists(download_path):
                    logging.info(f"Download completed: {download_path}")
                    return True
                time.sleep(1)

            logging.error(f"Download timed out after {timeout} seconds.")
            self.driver.save_screenshot("download_timeout.png")
            logging.info("Saved screenshot as download_timeout.png")
            return False

        except Exception as e:
            logging.error(f"Error during file download: {e}")
            self.driver.save_screenshot("download_error.png")
            logging.info("Saved screenshot as download_error.png")
            return False

    def close(self) -> None:
        """Close the WebDriver."""
        if self.driver:
            self.driver.quit()
            logging.info("WebDriver closed.")

def main() -> None:
    """Main function to execute the search tool."""
    query = "python "

    search_tool = AdvancedSearchTool(headless=False)  # headless=False for debugging
    try:
        result = search_tool.search(query=query)
        print(result)

        if result:
            logging.info(f"Search Results for '{result.query}':")

            logging.info(f"General URLs ({len(result.urls)}):")
            for url in result.urls[:5]:  # Display first 5 URLs
                logging.info(f" - {url}")

            logging.info(f"Image URLs ({len(result.image_urls)}):")
            for img_url in result.image_urls[:5]:  # Display first 5 Image URLs
                logging.info(f" - {img_url}")

            logging.info(f"Video URLs ({len(result.video_urls)}):")
            for vid_url in result.video_urls[:5]:  # Display first 5 Video URLs
                logging.info(f" - {vid_url}")
        else:
            logging.error("Failed to retrieve search results.")

        # Example usage of upload and download functionalities
        # Uncomment and modify the following lines as needed

        # Upload Example
        # upload_success = search_tool.upload_file(
        #     upload_url="https://the-internet.herokuapp.com/upload",
        #     file_path="path/to/your/file.png"
        # )
        # logging.info(f"Upload successful: {upload_success}")

        # Download Example
        # download_success = search_tool.download_file(
        #     download_url="https://www.selenium.dev/selenium/web/downloads/download.html",
        #     file_name="file_1.txt"
        # )
        # logging.info(f"Download successful: {download_success}")

    finally:
        search_tool.close()

if __name__ == "__main__":
    main()