# -*- coding: utf-8 -*-

import os
import sys
import json
import asyncio
import platform
import signal
import configparser
from functools import partial

# Import our RuntimeBridge for chrome.runtime API emulation
from shmcs.qtbrowser.runtime_bridge import RuntimeBridge, create_runtime_api_script

from PyQt6.QtCore import Qt, QUrl, QSize, QPoint
from PyQt6.QtWebChannel import QWebChannel
from PyQt6.QtGui import QIcon, QAction, QKeySequence, QFont, QColor, QPainter
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QTabWidget, QToolBar, QLineEdit,
    QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QDialog,
    QLabel, QMenu, QStyle, QMessageBox, QStatusBar,
    QInputDialog, QTextEdit
)
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebEngineCore import (
    QWebEngineProfile, QWebEngineSettings, QWebEnginePage, QWebEngineUrlScheme,
    QWebEngineScript
)

# Import Playwright for API compatibility
from playwright.async_api import async_playwright

from shmcs.qtbrowser.tabs import BrowserTab, DetachableTabBar
from shmcs.qtbrowser.chrome import ChromeUrlInterceptor, ChromeWebEnginePage
from shmcs.qtbrowser.extensions import ExtensionSchemeHandler, ExtensionDialog, ContentScriptInjector
from shmcs.qtbrowser.profiles import ProfileDialog

# Register URL schemes before any QApplication is created
def register_url_schemes():
    # Register qextension:// scheme
    qextension_scheme = QWebEngineUrlScheme(b"qextension")
    qextension_scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme |
                              QWebEngineUrlScheme.Flag.LocalScheme |
                              QWebEngineUrlScheme.Flag.LocalAccessAllowed |
                              QWebEngineUrlScheme.Flag.ServiceWorkersAllowed)
    QWebEngineUrlScheme.registerScheme(qextension_scheme)
    
    # Register chrome:// scheme
    chrome_scheme = QWebEngineUrlScheme(b"chrome")
    chrome_scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme |
                          QWebEngineUrlScheme.Flag.LocalScheme |
                          QWebEngineUrlScheme.Flag.LocalAccessAllowed |
                          QWebEngineUrlScheme.Flag.ServiceWorkersAllowed)
    QWebEngineUrlScheme.registerScheme(chrome_scheme)
    
    print("URL schemes registered")



class Browser(QMainWindow):
    """
    Main browser window that wraps the Playwright browser class.
    """
    instances = []

    def __init__(self, initial_url=None, debug=False, detached_tab=None, profile_path=None):
        super().__init__()
        Browser.instances.append(self)
        self.setWindowTitle("SHMCamStudio Browser")
        self.setWindowIcon(QIcon('assets/logo.jpg'))
        self.resize(1024, 768)

        # Create a central widget and layout
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        
        # Store loaded extensions
        self.loaded_extensions = {}

        # Create toolbar
        self.toolbar = QToolBar()
        self.toolbar.setMovable(False)
        self.toolbar.setIconSize(QSize(24, 24))

        # Add back button
        self.back_button = QPushButton()
        self.back_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_ArrowBack))
        self.back_button.setToolTip("Back")
        self.back_button.clicked.connect(self.navigate_back)
        self.toolbar.addWidget(self.back_button)

        # Add forward button
        self.forward_button = QPushButton()
        self.forward_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_ArrowForward))
        self.forward_button.setToolTip("Forward")
        self.forward_button.clicked.connect(self.navigate_forward)
        self.toolbar.addWidget(self.forward_button)

        # Add reload button
        self.reload_button = QPushButton()
        self.reload_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_BrowserReload))
        self.reload_button.setToolTip("Reload (F5)")
        self.reload_button.clicked.connect(self.reload_page)
        self.toolbar.addWidget(self.reload_button)

        # Add home button
        self.home_button = QPushButton()
        self.home_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_DirHomeIcon))
        self.home_button.setToolTip("Home")
        self.home_button.clicked.connect(self.navigate_home)
        self.toolbar.addWidget(self.home_button)

        # Add URL input
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("Enter URL...")
        self.url_input.returnPressed.connect(self.navigate_to_url)
        self.toolbar.addWidget(self.url_input)

        # The extension buttons will be inserted before this one, so we need its action.
        self.extensions_button = QPushButton()
        self.extensions_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_FileDialogDetailedView))
        self.extensions_button.setToolTip("Extensions")
        self.extensions_button.clicked.connect(self.show_extensions)
        self.extensions_button_action = self.toolbar.addWidget(self.extensions_button)

        """
        # Add Chrome URLs button with dropdown menu
        self.chrome_button = QPushButton()
        self.chrome_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_TitleBarMenuButton))
        self.chrome_button.setToolTip("Chrome URLs")
        self.chrome_menu = QMenu(self)
        
        # Add common chrome:// URLs to the menu
        chrome_urls = {
            "Extensions": "chrome://extensions/",
            "Settings": "chrome://settings/",
            "History": "chrome://history/",
            "Bookmarks": "chrome://bookmarks/",
            "Downloads": "chrome://downloads/",
            "Flags": "chrome://flags/",
            "Version": "chrome://version/",
            "GPU": "chrome://gpu/",
            "Network": "chrome://net-internals/",
            "Inspect": "chrome://inspect/",
            "Media": "chrome://media-internals/",
            "Components": "chrome://components/",
            "System": "chrome://system/",
            "Chrome URLs": "chrome://chrome-urls/"  # This shows all available chrome:// URLs
        }
        
        # Add a separator and debug options
        self.chrome_menu.addSeparator()
        debug_action = self.chrome_menu.addAction("Debug Chrome URLs")
        debug_action.triggered.connect(self.debug_chrome_urls)
        
        for name, url in chrome_urls.items():
            action = self.chrome_menu.addAction(name)
            action.triggered.connect(lambda checked, u=url: self.navigate_to_chrome_url(u))
        
        self.chrome_button.setMenu(self.chrome_menu)
        self.toolbar.addWidget(self.chrome_button)
        """
        
        # Add new window button
        self.new_window_button = QPushButton()
        self.new_window_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_FileIcon))
        self.new_window_button.setToolTip("New Window (Ctrl+W)")
        self.new_window_button.clicked.connect(self.open_new_window)
        self.toolbar.addWidget(self.new_window_button)

        if debug:
            self.debug_button = QPushButton()
            self.debug_button.setIcon(self._get_themed_icon(QStyle.StandardPixmap.SP_MessageBoxWarning))
            self.debug_button.setToolTip("Toggle Developer Tools")
            self.debug_button.clicked.connect(self.toggle_devtools)
            self.toolbar.addWidget(self.debug_button)

            # Add a test extension button to the toolbar
            self.test_extension_button = QPushButton("Test Extension")
            self.test_extension_button.setToolTip("Launch Test Extension")
            self.test_extension_button.clicked.connect(self.launch_test_extension)
            self.toolbar.addWidget(self.test_extension_button)

        self.layout.addWidget(self.toolbar)

        # Create tab widget
        self.tabs = QTabWidget()
        self.tab_bar = DetachableTabBar()
        self.tabs.setTabBar(self.tab_bar)
        self.tab_bar.tabDetached.connect(self.handle_tab_detached)
        
        self.tabs.setTabsClosable(True)
        # self.tabs.setMovable(True) # This is handled by our DetachableTabBar
        self.tabs.setDocumentMode(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)
        self.tabs.currentChanged.connect(self.tab_changed)

        self.layout.addWidget(self.tabs)

        # Add status bar
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)

        # Add a new tab button
        self.tabs.setCornerWidget(self._create_new_tab_button(), Qt.Corner.TopRightCorner)

        # Set the home URL from config
        config = configparser.ConfigParser()
        config.read('shmcamstudio.conf')
        self.home_url = config.get('Browser', 'home_url', fallback='https://www.google.com')

        # Centralized browser profile
        if not profile_path:
            # This should not happen if main is used, but as a fallback
            profile_path = "data/browser_profile_default"
        self.profile_dir = profile_path
        if not os.path.exists(self.profile_dir):
            os.makedirs(self.profile_dir)
        
        # Extensions must be in a specific subdirectory of the profile
        self.extensions_dir = os.path.join(self.profile_dir, "Default", "Extensions")
        if not os.path.exists(self.extensions_dir):
            os.makedirs(self.extensions_dir)
            
        self.profile = QWebEngineProfile(self.profile_dir, self)
        
        # Enable extension developer mode to allow loading unpacked extensions
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.AllowWindowActivationFromJavaScript, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.AllowRunningInsecureContent, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanPaste, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalStorageEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.WebGLEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.PluginsEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.ErrorPageEnabled, False)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
        # Enable access to chrome:// URLs and other special URLs
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
        
        # Additional settings to ensure chrome:// URLs work
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.ErrorPageEnabled, False)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled, True)
        
        # Set developer mode flag in preferences
        self.profile.setHttpUserAgent(self.profile.httpUserAgent() + " ChromiumExtensionDevMode")
        
        # Enable Autofill feature for QWebEngine (using preferences instead of WebAttribute)
        # Note: AutoFillEnabled attribute is not available in this PyQt6 version
        
        # Create a directory for extension preferences if it doesn't exist
        prefs_dir = os.path.join(self.profile_dir, "Default")
        if not os.path.exists(prefs_dir):
            os.makedirs(prefs_dir)
            
        # Create or update the Preferences file to enable extension developer mode
        prefs_file = os.path.join(prefs_dir, "Preferences")
        prefs_data = {}
        if os.path.exists(prefs_file):
            try:
                with open(prefs_file, 'r') as f:
                    prefs_data = json.load(f)
            except json.JSONDecodeError:
                # If the file exists but is invalid JSON, start with an empty dict
                pass
        
        # Set extension developer mode preferences
        if 'extensions' not in prefs_data:
            prefs_data['extensions'] = {}
        prefs_data['extensions']['developer_mode'] = True
        
        # Enable unpacked extensions and user scripts
        if 'extensions' in prefs_data:
            # Allow loading unpacked extensions
            prefs_data['extensions']['allow_file_access'] = True
            # Allow user scripts (required by some extensions like Lovense)
            prefs_data['extensions']['allow_user_scripts'] = True
        
        # Enable Autofill in preferences
        if 'autofill' not in prefs_data:
            prefs_data['autofill'] = {}
        prefs_data['autofill']['enabled'] = True
        
        # Enable additional features for extensions
        if 'browser' not in prefs_data:
            prefs_data['browser'] = {}
        if 'enabled_labs_experiments' not in prefs_data['browser']:
            prefs_data['browser']['enabled_labs_experiments'] = []
        
        # Add Autofill experiments if not already present
        autofill_experiments = [
            "enable-autofill-credit-card-upload",
            "enable-autofill-credit-card-authentication",
            "enable-autofill-address-save-prompts",
            "enable-experimental-web-platform-features"
        ]
        
        for experiment in autofill_experiments:
            if experiment not in prefs_data['browser']['enabled_labs_experiments']:
                prefs_data['browser']['enabled_labs_experiments'].append(experiment)
        
        # Write the updated preferences back to the file
        with open(prefs_file, 'w') as f:
            json.dump(prefs_data, f, indent=2)
        
        # Check for Lovense extension and configure it specifically
        lovense_dir = os.path.join(self.extensions_dir, "lovense")
        if os.path.exists(lovense_dir):
            print("Lovense extension found, applying special configuration...")
            
            # Create secure preferences file if it doesn't exist
            secure_prefs_file = os.path.join(self.profile_dir, "Default", "Secure Preferences")
            secure_prefs_data = {}
            
            if os.path.exists(secure_prefs_file):
                try:
                    with open(secure_prefs_file, 'r') as f:
                        secure_prefs_data = json.load(f)
                except:
                    secure_prefs_data = {}
            
            # Ensure extensions section exists
            if 'extensions' not in secure_prefs_data:
                secure_prefs_data['extensions'] = {}
            
            # Add settings for Lovense
            if 'settings' not in secure_prefs_data['extensions']:
                secure_prefs_data['extensions']['settings'] = {}
            
            # Set Lovense as trusted
            secure_prefs_data['extensions']['settings']["lovense"] = {
                "ack_external_install_prompt": True,
                "installed_by_default": False,
                "installed_by_oem": False,
                "installed_by_policy": False,
                "mark_acknowledged_external_install": True,
                "was_installed_by_enterprise_policy": False
            }
            
            # Write secure preferences
            with open(secure_prefs_file, 'w') as f:
                json.dump(secure_prefs_data, f, indent=2)
            
            # Create Local State file with extension settings
            local_state_file = os.path.join(self.profile_dir, "Local State")
            local_state_data = {}
            
            if os.path.exists(local_state_file):
                try:
                    with open(local_state_file, 'r') as f:
                        local_state_data = json.load(f)
                except:
                    local_state_data = {}
            
            # Ensure extensions section exists
            if 'extensions' not in local_state_data:
                local_state_data['extensions'] = {}
            
            # Enable developer mode in local state
            local_state_data['extensions']['ui'] = {
                "developer_mode": True
            }
            
            # Write local state
            with open(local_state_file, 'w') as f:
                json.dump(local_state_data, f, indent=2)
            
            print("Lovense extension configuration complete")
            
        # Update loaded extensions list
        self.update_extensions_list()

        # Install URL scheme handlers
        self.extension_scheme_handler = ExtensionSchemeHandler(self.extensions_dir, self.loaded_extensions)
        # Reinstall URL scheme handlers
        self.profile.installUrlSchemeHandler(b"qextension", self.extension_scheme_handler)
        
        # Re-register the RuntimeBridge with the QWebChannel
        self.web_channel = QWebChannel(self)
        self.runtime_bridge = RuntimeBridge(self, self.extensions_dir, self)
        self.web_channel.registerObject("runtimeBridge", self.runtime_bridge)
        
        # Initialize the content script injector
        self.content_script_injector = ContentScriptInjector(self.extensions_dir)
        
        # Register chrome:// protocol interceptor
        QWebEngineProfile.defaultProfile().setUrlRequestInterceptor(
            ChromeUrlInterceptor(self)
        )
        
        # Add the chrome.runtime API script to the profile's scripts
        self.runtime_api_script = create_runtime_api_script()
        self.profile.scripts().insert(self.runtime_api_script)
        
        
        if detached_tab:
            widget, title = detached_tab
            index = self.tabs.addTab(widget, title)
            self.tabs.setCurrentIndex(index)
            widget.browser = self
            widget.urlChanged.connect(self.update_url)
            widget.titleChanged.connect(lambda t, tab=widget: self.update_title(t, tab))
            widget.loadStatusChanged.connect(self.update_status_bar)
            if hasattr(widget, 'web_view'):
                self.update_title(widget.web_view.title(), widget)
                self.update_url(widget.web_view.url().toString())
        else:
            # Create a new tab on startup
            url_to_open = initial_url if initial_url is not None else self.home_url
            self.new_page(url_to_open)

        # Set up keyboard shortcuts
        self._setup_shortcuts()

        # Store Playwright objects
        self.playwright = None
        self.playwright_browser = None
        self.browser_contexts = {}
        self.dev_tools_windows = []
        self.open_extension_popups = []
        self.extension_actions = []

        self.update_extension_buttons()

    
    def closeEvent(self, event):
        if self in Browser.instances:
            Browser.instances.remove(self)
        super().closeEvent(event)
    
    def _get_themed_icon(self, standard_pixmap, color="white"):
        """Create a themed icon from a standard pixmap."""
        icon = self.style().standardIcon(standard_pixmap)
        pixmap = icon.pixmap(self.toolbar.iconSize())
        painter = QPainter(pixmap)
        painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn)
        painter.fillRect(pixmap.rect(), QColor(color))
        painter.end()
        return QIcon(pixmap)
    
    def _create_new_tab_button(self):
        """Create a button for adding new tabs."""
        button = QPushButton("+")
        button.setToolTip("New Tab")
        button.clicked.connect(lambda: self.new_page(self.home_url))
        return button
    
    def _setup_shortcuts(self):
        """Set up keyboard shortcuts."""
        # Ctrl+T: New Tab
        new_tab_shortcut = QAction("New Tab", self)
        new_tab_shortcut.setShortcut(QKeySequence("Ctrl+T"))
        new_tab_shortcut.triggered.connect(lambda: self.new_page(self.home_url))
        self.addAction(new_tab_shortcut)

        # Ctrl+Tab: Cycle Tabs
        cycle_tabs_shortcut = QAction("Cycle Tabs", self)
        cycle_tabs_shortcut.setShortcut(QKeySequence("Ctrl+Tab"))
        cycle_tabs_shortcut.triggered.connect(self.cycle_tabs)
        self.addAction(cycle_tabs_shortcut)

        # Ctrl+W: New Window
        new_window_shortcut = QAction("New Window", self)
        new_window_shortcut.setShortcut(QKeySequence("Ctrl+W"))
        new_window_shortcut.triggered.connect(self.open_new_window)
        self.addAction(new_window_shortcut)

        # Ctrl+L: Focus URL bar
        focus_url_shortcut = QAction("Focus URL", self)
        focus_url_shortcut.setShortcut(QKeySequence("Ctrl+L"))
        focus_url_shortcut.triggered.connect(self.url_input.setFocus)
        self.addAction(focus_url_shortcut)

        # F5: Reload page
        reload_shortcut = QAction("Reload", self)
        reload_shortcut.setShortcut(QKeySequence("F5"))
        reload_shortcut.triggered.connect(self.reload_page)
        self.addAction(reload_shortcut)
    
    def cycle_tabs(self):
        """Cycle through the open tabs."""
        if self.tabs.count() > 1:
            next_index = (self.tabs.currentIndex() + 1) % self.tabs.count()
            self.tabs.setCurrentIndex(next_index)

    def on_tab_removed(self):
        """Close the window if the last tab is removed."""
        if self.tabs.count() == 0:
            self.close()

    def handle_tab_detached(self, index, pos):
        """Handle a tab being detached to a new window."""
        if index < 0 or index >= self.tabs.count():
            return

        widget = self.tabs.widget(index)
        title = self.tabs.tabText(index)

        try:
            widget.urlChanged.disconnect(self.update_url)
            widget.titleChanged.disconnect()
            widget.loadStatusChanged.disconnect(self.update_status_bar)
        except (TypeError, RuntimeError):
            pass

        # Create a new browser instance, which will take ownership of the widget.
        new_browser = Browser(
            debug=("--debug" in sys.argv),
            detached_tab=(widget, title),
            profile_path=self.profile_dir
        )
        
        new_browser.setGeometry(self.geometry())
        new_browser.move(pos - QPoint(new_browser.width() // 4, 10))
        new_browser.show()

        # Now that the widget is safely reparented, remove the tab from the old browser.
        # The on_tab_removed method will handle closing the window if it's empty.
        self.tabs.removeTab(index)
        self.on_tab_removed()

    def new_page(self, url="about:blank"):
        """Create a new browser tab with the specified URL."""
        # Create a new tab
        tab = BrowserTab(parent=self.tabs, url=url, profile=self.profile)
        # Store a reference to the Browser instance
        tab.browser = self
        tab.urlChanged.connect(self.update_url)
        tab.titleChanged.connect(lambda title, tab=tab: self.update_title(title, tab))
        tab.loadStatusChanged.connect(self.update_status_bar)
        
        # Add the tab to the tab widget
        index = self.tabs.addTab(tab, "New Tab")
        self.tabs.setCurrentIndex(index)
        
        return tab
    
    def close_tab(self, index):
        """Close the tab at the specified index."""
        if index < 0 or index >= self.tabs.count():
            return
        
        # Get the tab widget and schedule it for deletion.
        tab = self.tabs.widget(index)
        if tab:
            tab.deleteLater()
        
        # Remove the tab from the tab bar.
        self.tabs.removeTab(index)
        self.on_tab_removed()
    
    def tab_changed(self, index):
        """Handle tab change events."""
        if index < 0:
            return
        
        # Update the URL input
        tab = self.tabs.widget(index)
        if hasattr(tab, 'url'):
            self.url_input.setText(tab.url)
        self.update_status_bar()
    
    def update_url(self, url):
        """Update the URL input when the page URL changes."""
        self.url_input.setText(url)
        
        # Update the tab's stored URL
        current_tab = self.tabs.currentWidget()
        if current_tab:
            current_tab.url = url
    
    def update_title(self, title, tab):
        """Update the tab title when the page title changes."""
        index = self.tabs.indexOf(tab)
        if index >= 0:
            self.tabs.setTabText(index, title or "New Tab")
    
    def navigate_to_url(self):
        """Navigate to the URL in the URL input."""
        url = self.url_input.text().strip()
        
        # Add http:// if no protocol is specified
        if url and not url.startswith(("http://", "https://", "file://", "about:", "chrome://", "qextension://", "qrc://")):
            url = "http://" + url
        
        # Navigate the current tab
        current_tab = self.tabs.currentWidget()
        if current_tab:
            current_tab.navigate(url)
    
    def navigate_home(self):
        """Navigate to the home URL."""
        current_tab = self.tabs.currentWidget()
        if current_tab:
            current_tab.navigate(self.home_url)
            
    def navigate_to_chrome_url(self, url):
        """Navigate to a chrome:// URL."""
        print(f"Navigating to chrome URL: {url}")
        
        # Create a new tab specifically for chrome:// URLs
        tab = self.new_page("about:blank")
        
        # Ensure the tab is using our custom ChromeWebEnginePage
        if hasattr(tab, 'web_view'):
            # If the page isn't already a ChromeWebEnginePage, replace it
            if not isinstance(tab.web_view.page(), ChromeWebEnginePage):
                page = ChromeWebEnginePage(self.profile, tab.web_view)
                tab.web_view.setPage(page)
            
            # Now navigate to the chrome:// URL
            tab.web_view.load(QUrl(url))
            print(f"Created new tab for chrome URL: {url}")

    def navigate_back(self):
        """Navigate back in the current tab."""
        current_tab = self.tabs.currentWidget()
        if current_tab and hasattr(current_tab, 'web_view'):
            current_tab.web_view.back()

    def navigate_forward(self):
        """Navigate forward in the current tab."""
        current_tab = self.tabs.currentWidget()
        if current_tab and hasattr(current_tab, 'web_view'):
            current_tab.web_view.forward()

    def reload_page(self):
        """Reload the current tab."""
        current_tab = self.tabs.currentWidget()
        if current_tab and hasattr(current_tab, 'web_view'):
            current_tab.web_view.reload()
    
    def open_new_window(self):
        """Open a new browser window."""
        new_browser = Browser(debug="--debug" in sys.argv, profile_path=self.profile_dir)
        new_browser.show()
    
    def toggle_devtools(self):
        """Opens the remote developer tools URL in a new window or shows extension debug info."""
        # Create a dialog to show debug options
        debug_dialog = QDialog(self)
        debug_dialog.setWindowTitle("Developer Tools")
        debug_dialog.resize(1024, 768)
        
        layout = QVBoxLayout()
        
        # Add tabs for different debug options
        tabs = QTabWidget()
        
        # Tab 1: Remote DevTools
        remote_tab = QWidget()
        remote_layout = QVBoxLayout(remote_tab)
        web_view = QWebEngineView()
        web_view.load(QUrl("http://localhost:9222"))
        remote_layout.addWidget(web_view)
        
        # Tab 2: Extension Debug Info
        ext_tab = QWidget()
        ext_layout = QVBoxLayout(ext_tab)
        
        # Add a text area to show preferences file content
        prefs_label = QLabel("Preferences File Content:")
        ext_layout.addWidget(prefs_label)
        
        prefs_text = QTextEdit()
        prefs_text.setReadOnly(True)
        ext_layout.addWidget(prefs_text)
        
        # Add a button to refresh the preferences content
        refresh_button = QPushButton("Refresh Preferences")
        ext_layout.addWidget(refresh_button)
        
        # Add a button to force enable developer mode
        force_button = QPushButton("Force Enable Developer Mode")
        ext_layout.addWidget(force_button)
        
        # Add a button specifically for fixing the Lovense extension
        lovense_button = QPushButton("Fix Lovense Extension")
        ext_layout.addWidget(lovense_button)
        
        # Function to load and display preferences
        def load_preferences():
            prefs_file = os.path.join(self.profile_dir, "Default", "Preferences")
            if os.path.exists(prefs_file):
                try:
                    with open(prefs_file, 'r') as f:
                        prefs_data = json.load(f)
                    
                    # Format the JSON for better readability
                    formatted_json = json.dumps(prefs_data, indent=2)
                    prefs_text.setText(formatted_json)
                    
                    # Highlight extension developer mode status
                    ext_dev_mode = prefs_data.get('extensions', {}).get('developer_mode', False)
                    allow_file_access = prefs_data.get('extensions', {}).get('allow_file_access', False)
                    allow_user_scripts = prefs_data.get('extensions', {}).get('allow_user_scripts', False)
                    
                    status_text = f"Extension Developer Mode: {ext_dev_mode}\n"
                    status_text += f"Allow File Access: {allow_file_access}\n"
                    status_text += f"Allow User Scripts: {allow_user_scripts}\n"
                    
                    QMessageBox.information(debug_dialog, "Extension Settings Status", status_text)
                    
                except Exception as e:
                    prefs_text.setText(f"Error loading preferences: {e}")
            else:
                prefs_text.setText("Preferences file not found")
        
        # Function to force enable developer mode
        def force_developer_mode():
            prefs_file = os.path.join(self.profile_dir, "Default", "Preferences")
            if os.path.exists(prefs_file):
                try:
                    with open(prefs_file, 'r') as f:
                        prefs_data = json.load(f)
                    
                    # Ensure extensions section exists
                    if 'extensions' not in prefs_data:
                        prefs_data['extensions'] = {}
                    
                    # Force enable all developer mode settings
                    prefs_data['extensions']['developer_mode'] = True
                    prefs_data['extensions']['allow_file_access'] = True
                    prefs_data['extensions']['allow_user_scripts'] = True
                    
                    # Write back to file
                    with open(prefs_file, 'w') as f:
                        json.dump(prefs_data, f, indent=2)
                    
                    # Reload the profile
                    self.reload_profile_and_tabs()
                    
                    QMessageBox.information(debug_dialog, "Success",
                                           "Developer mode forcefully enabled. Profile reloaded.")
                    
                    # Refresh the displayed preferences
                    load_preferences()
                    
                except Exception as e:
                    QMessageBox.critical(debug_dialog, "Error", f"Could not force developer mode: {e}")
            else:
                QMessageBox.warning(debug_dialog, "Error", "Preferences file not found")
        
        # Function to specifically fix the Lovense extension
        def fix_lovense_extension():
            # Check if Lovense extension exists
            lovense_dir = os.path.join(self.extensions_dir, "lovense")
            if not os.path.exists(lovense_dir):
                QMessageBox.warning(debug_dialog, "Error", "Lovense extension not found in extensions directory")
                return
                
            try:
                # 1. Update preferences file with specific settings for Lovense
                prefs_file = os.path.join(self.profile_dir, "Default", "Preferences")
                if os.path.exists(prefs_file):
                    with open(prefs_file, 'r') as f:
                        prefs_data = json.load(f)
                    
                    # Ensure extensions section exists
                    if 'extensions' not in prefs_data:
                        prefs_data['extensions'] = {}
                    
                    # Force enable all developer mode settings
                    prefs_data['extensions']['developer_mode'] = True
                    prefs_data['extensions']['allow_file_access'] = True
                    prefs_data['extensions']['allow_user_scripts'] = True
                    
                    # Add specific settings for Lovense extension
                    if 'settings' not in prefs_data['extensions']:
                        prefs_data['extensions']['settings'] = {}
                    
                    # Get Lovense extension ID (directory name)
                    lovense_id = "lovense"
                    
                    # Set specific permissions for Lovense
                    prefs_data['extensions']['settings'][lovense_id] = {
                        "active_permissions": {
                            "api": ["storage", "unlimitedStorage", "userScripts", "desktopCapture"],
                            "explicit_host": ["<all_urls>"],
                            "manifest_permissions": [],
                            "scriptable_host": ["<all_urls>"]
                        },
                        "granted_permissions": {
                            "api": ["storage", "unlimitedStorage", "userScripts", "desktopCapture"],
                            "explicit_host": ["<all_urls>"],
                            "manifest_permissions": [],
                            "scriptable_host": ["<all_urls>"]
                        },
                        "location": 1,  # 1 = unpacked extension
                        "runtime_allowed_hosts": ["*://*.lovense.com/*", "*://localhost/*"],
                        "runtime_blocked_hosts": []
                    }
                    
                    # Write back to file
                    with open(prefs_file, 'w') as f:
                        json.dump(prefs_data, f, indent=2)
                
                # 2. Create a secure_preferences file if it doesn't exist
                secure_prefs_file = os.path.join(self.profile_dir, "Default", "Secure Preferences")
                secure_prefs_data = {}
                
                if os.path.exists(secure_prefs_file):
                    try:
                        with open(secure_prefs_file, 'r') as f:
                            secure_prefs_data = json.load(f)
                    except:
                        secure_prefs_data = {}
                
                # Ensure extensions section exists
                if 'extensions' not in secure_prefs_data:
                    secure_prefs_data['extensions'] = {}
                
                # Add settings for Lovense
                if 'settings' not in secure_prefs_data['extensions']:
                    secure_prefs_data['extensions']['settings'] = {}
                
                # Set Lovense as trusted
                secure_prefs_data['extensions']['settings']["lovense"] = {
                    "ack_external_install_prompt": True,
                    "installed_by_default": False,
                    "installed_by_oem": False,
                    "installed_by_policy": False,
                    "mark_acknowledged_external_install": True,
                    "was_installed_by_enterprise_policy": False
                }
                
                # Write secure preferences
                with open(secure_prefs_file, 'w') as f:
                    json.dump(secure_prefs_data, f, indent=2)
                
                # 3. Create Local State file with extension settings
                local_state_file = os.path.join(self.profile_dir, "Local State")
                local_state_data = {}
                
                if os.path.exists(local_state_file):
                    try:
                        with open(local_state_file, 'r') as f:
                            local_state_data = json.load(f)
                    except:
                        local_state_data = {}
                
                # Ensure extensions section exists
                if 'extensions' not in local_state_data:
                    local_state_data['extensions'] = {}
                
                # Enable developer mode in local state
                local_state_data['extensions']['ui'] = {
                    "developer_mode": True
                }
                
                # Write local state
                with open(local_state_file, 'w') as f:
                    json.dump(local_state_data, f, indent=2)
                
                # Reload the profile
                self.reload_profile_and_tabs()
                
                QMessageBox.information(debug_dialog, "Success",
                                       "Lovense extension has been fixed and profile reloaded.")
                
                # Refresh the displayed preferences
                load_preferences()
                
            except Exception as e:
                QMessageBox.critical(debug_dialog, "Error", f"Could not fix Lovense extension: {e}")
        
        # Connect buttons to functions
        refresh_button.clicked.connect(load_preferences)
        force_button.clicked.connect(force_developer_mode)
        lovense_button.clicked.connect(fix_lovense_extension)
        
        # Load preferences initially
        load_preferences()
        
        # Add tabs to the tab widget
        tabs.addTab(remote_tab, "Remote DevTools")
        tabs.addTab(ext_tab, "Extension Debug")
        
        layout.addWidget(tabs)
        debug_dialog.setLayout(layout)
        debug_dialog.show()
        
        self.dev_tools_windows.append(debug_dialog)
        debug_dialog.finished.connect(lambda: self.dev_tools_windows.remove(debug_dialog))

    def update_status_bar(self):
        """Update the status bar based on the current tab's state."""
        current_tab = self.tabs.currentWidget()
        if not current_tab:
            self.status_bar.showMessage("Ready")
            return
        
        if current_tab.is_loading:
            self.status_bar.showMessage("Loading...")
        else:
            self.status_bar.showMessage("Ready")

    def reload_profile_and_tabs(self):
        """Reloads the browser profile and recreates pages in all tabs."""
        print("Reloading profile to apply extension changes...")

        # 1. Save the URLs and current index of all open tabs
        urls = []
        current_index = self.tabs.currentIndex()
        for i in range(self.tabs.count()):
            tab = self.tabs.widget(i)
            if hasattr(tab, 'web_view') and tab.web_view.url().isValid():
                urls.append(tab.web_view.url().toString())
            else:
                urls.append("about:blank")

        # 2. Store the old profile to delete it later
        old_profile = self.profile
        old_profile.clearHttpCache()

        # 3. Clear all existing tabs. This removes references to pages using the old profile.
        self.tabs.clear()

        # 4. Create a new profile object. This forces a re-read from disk because
        #    the old one will be properly deleted.
        self.profile = QWebEngineProfile(self.profile_dir, self)
        
        # Re-enable extension developer mode and Autofill settings
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.AllowWindowActivationFromJavaScript, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.AllowRunningInsecureContent, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanPaste, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.LocalStorageEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.WebGLEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.PluginsEnabled, True)
        self.profile.settings().setAttribute(QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, True)
        
        # Set developer mode flag in preferences
        self.profile.setHttpUserAgent(self.profile.httpUserAgent() + " ChromiumExtensionDevMode")
        
        # Re-apply extension developer mode settings to preferences file
        prefs_dir = os.path.join(self.profile_dir, "Default")
        prefs_file = os.path.join(prefs_dir, "Preferences")
        if os.path.exists(prefs_file):
            try:
                with open(prefs_file, 'r') as f:
                    prefs_data = json.load(f)
                
                # Ensure extension developer mode is enabled
                if 'extensions' not in prefs_data:
                    prefs_data['extensions'] = {}
                prefs_data['extensions']['developer_mode'] = True
                prefs_data['extensions']['allow_file_access'] = True
                prefs_data['extensions']['allow_user_scripts'] = True
                
                # Write the updated preferences back to the file
                with open(prefs_file, 'w') as f:
                    json.dump(prefs_data, f, indent=2)
                    
                # Check for Lovense extension and reconfigure it
                lovense_dir = os.path.join(self.extensions_dir, "lovense")
                if os.path.exists(lovense_dir):
                    print("Lovense extension found during reload, reapplying special configuration...")
                    
                    # Update specific settings for Lovense extension in preferences
                    if 'settings' not in prefs_data['extensions']:
                        prefs_data['extensions']['settings'] = {}
                    
                    # Set specific permissions for Lovense
                    prefs_data['extensions']['settings']["lovense"] = {
                        "active_permissions": {
                            "api": ["storage", "unlimitedStorage", "userScripts", "desktopCapture"],
                            "explicit_host": ["<all_urls>"],
                            "manifest_permissions": [],
                            "scriptable_host": ["<all_urls>"]
                        },
                        "granted_permissions": {
                            "api": ["storage", "unlimitedStorage", "userScripts", "desktopCapture"],
                            "explicit_host": ["<all_urls>"],
                            "manifest_permissions": [],
                            "scriptable_host": ["<all_urls>"]
                        },
                        "location": 1,  # 1 = unpacked extension
                        "runtime_allowed_hosts": ["*://*.lovense.com/*", "*://localhost/*"],
                        "runtime_blocked_hosts": []
                    }
                    
                    # Write updated preferences with Lovense settings
                    with open(prefs_file, 'w') as f:
                        json.dump(prefs_data, f, indent=2)
                    
                    # Update secure preferences
                    secure_prefs_file = os.path.join(self.profile_dir, "Default", "Secure Preferences")
                    secure_prefs_data = {}
                    
                    if os.path.exists(secure_prefs_file):
                        try:
                            with open(secure_prefs_file, 'r') as f:
                                secure_prefs_data = json.load(f)
                        except:
                            secure_prefs_data = {}
                    
                    # Ensure extensions section exists
                    if 'extensions' not in secure_prefs_data:
                        secure_prefs_data['extensions'] = {}
                    
                    # Add settings for Lovense
                    if 'settings' not in secure_prefs_data['extensions']:
                        secure_prefs_data['extensions']['settings'] = {}
                    
                    # Set Lovense as trusted
                    secure_prefs_data['extensions']['settings']["lovense"] = {
                        "ack_external_install_prompt": True,
                        "installed_by_default": False,
                        "installed_by_oem": False,
                        "installed_by_policy": False,
                        "mark_acknowledged_external_install": True,
                        "was_installed_by_enterprise_policy": False
                    }
                    
                    # Write secure preferences
                    with open(secure_prefs_file, 'w') as f:
                        json.dump(secure_prefs_data, f, indent=2)
                    
                    # Update Local State file
                    local_state_file = os.path.join(self.profile_dir, "Local State")
                    local_state_data = {}
                    
                    if os.path.exists(local_state_file):
                        try:
                            with open(local_state_file, 'r') as f:
                                local_state_data = json.load(f)
                        except:
                            local_state_data = {}
                    
                    # Ensure extensions section exists
                    if 'extensions' not in local_state_data:
                        local_state_data['extensions'] = {}
                    
                    # Enable developer mode in local state
                    local_state_data['extensions']['ui'] = {
                        "developer_mode": True
                    }
                    
                    # Write local state
                    with open(local_state_file, 'w') as f:
                        json.dump(local_state_data, f, indent=2)
                    
                    print("Lovense extension reconfiguration complete during reload")
            except Exception as e:
                print(f"Error updating preferences file during reload: {e}")
        
        self.profile.installUrlSchemeHandler(b"qextension", self.extension_scheme_handler)
        
        # 5. Re-create all tabs with the new profile
        if not urls: # Ensure there's at least one tab
            urls.append(self.home_url)
            
        for url in urls:
            self.new_page(url)
        
        # 6. Restore the previously active tab
        if current_index != -1 and current_index < len(urls):
            self.tabs.setCurrentIndex(current_index)
            
        # 7. Reinitialize the content script injector
        self.content_script_injector = ContentScriptInjector(self.extensions_dir)
        
        # 8. Schedule the old profile for deletion. This is crucial.
        old_profile.setParent(None)
        old_profile.deleteLater()

        print("Profile and tabs reloaded.")
        self.update_extension_buttons()

    def open_extension_popup_from_toolbar(self, ext_path):
        """Opens an extension's popup from a toolbar button click."""
        ext_name = os.path.basename(ext_path)
        manifest_path = os.path.join(ext_path, "manifest.json")

        if not os.path.exists(manifest_path):
            QMessageBox.warning(self, "Error", "manifest.json not found for this extension.")
            return

        try:
            with open(manifest_path, 'r', encoding='utf-8') as f:
                manifest = json.load(f)
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Could not read manifest.json: {e}")
            return

        popup_path = None
        action = manifest.get('action') or manifest.get('browser_action') or manifest.get('page_action')
        if action and action.get('default_popup'):
            popup_path = action.get('default_popup')

        if not popup_path:
            # This should not happen if the button was created, but as a safeguard:
            QMessageBox.information(self, "No Popup", "This extension does not have a popup.")
            return

        popup_file = os.path.join(ext_path, popup_path)
        if not os.path.exists(popup_file):
            QMessageBox.warning(self, "Error", f"Popup file not found: {popup_path}")
            return

        # Open the popup in a new non-modal dialog
        popup_dialog = QDialog(self)
        popup_dialog.setWindowTitle(manifest.get("name", "Extension Popup"))
        layout = QVBoxLayout(popup_dialog)
        web_view = QWebEngineView()
        
        # The 'self' here is the Browser instance, so self.profile is correct
        page = QWebEnginePage(self.profile, web_view)
        web_view.setPage(page)
        
        # Set up QWebChannel for the page to enable chrome.runtime API
        page.setWebChannel(self.web_channel)
        
        # Explicitly initialize the QWebChannel with a script
        init_script = """
            // Create a global variable to track if transport is ready
            window.__qtWebChannelTransportReady = false;
            
            function initializeWebChannel() {
                if (typeof qt !== 'undefined' && qt.webChannelTransport) {
                    try {
                        // Check if QWebChannel is defined
                        if (typeof QWebChannel === 'undefined') {
                            console.log("QWebChannel is not defined yet, will retry later");
                            return false;
                        }
                        
                        new QWebChannel(qt.webChannelTransport, function(channel) {
                            window.channel = channel;
                            window.runtimeBridge = channel.objects.runtimeBridge;
                            window.__qtWebChannelTransportReady = true;
                            console.log("QWebChannel initialized successfully for extension popup");
                            
                            // Dispatch an event to notify that the channel is ready
                            document.dispatchEvent(new CustomEvent('webChannelReady', {
                                detail: { channel: channel }
                            }));
                            
                            // Also dispatch the chrome.runtime.initialized event
                            document.dispatchEvent(new CustomEvent('chrome.runtime.initialized', {
                                detail: { extensionId: "%s" }
                            }));
                        });
                        return true;
                    } catch (e) {
                        console.error("Error initializing QWebChannel:", e);
                        return false;
                    }
                } else {
                    console.log("qt.webChannelTransport not available yet, will retry later");
                    return false;
                }
            }
            
            // Try to initialize immediately
            if (!initializeWebChannel()) {
                // If it fails, set up a retry mechanism
                let retryCount = 0;
                const MAX_RETRIES = 50;
                
                const retryInterval = setInterval(function() {
                    console.log("Retrying QWebChannel initialization... (attempt " + (retryCount + 1) + " of " + MAX_RETRIES + ")");
                    if (initializeWebChannel() || retryCount >= MAX_RETRIES) {
                        clearInterval(retryInterval);
                        if (retryCount >= MAX_RETRIES) {
                            console.error("Failed to initialize QWebChannel after " + MAX_RETRIES + " attempts");
                        }
                    }
                    retryCount++;
                }, 200);
            }
        """ % ext_name
        
        # Run the initialization script before loading the URL
        page.runJavaScript(init_script, lambda result: print("QWebChannel initialization script executed for popup"))

        popup_url = QUrl(f"qextension://{ext_name}/{popup_path}")
        web_view.load(popup_url)
        
        layout.addWidget(web_view)
        popup_dialog.setLayout(layout)
        popup_dialog.resize(400, 600)
        
        popup_dialog.show()
        
        # Keep a reference to prevent garbage collection
        self.open_extension_popups.append(popup_dialog)
        popup_dialog.finished.connect(lambda: self.open_extension_popups.remove(popup_dialog))

    def update_extensions_list(self):

        if not self.extensions_dir or not os.path.exists(self.extensions_dir):
            return

        # refresh the loaded_extension list
        self.loaded_extensions = {}

        # Find all enabled extension directories
        for ext_name in sorted(os.listdir(self.extensions_dir)):
            if ext_name.endswith(".disabled"):
                continue

            ext_path = os.path.join(self.extensions_dir, ext_name)
            if not os.path.isdir(ext_path):
                continue

            manifest_path = os.path.join(ext_path, "manifest.json")
            if not os.path.exists(manifest_path):
                continue

            try:
                with open(manifest_path, 'r', encoding='utf-8') as f:
                    manifest = json.load(f)
            except Exception as e:
                print(f"Error loading manifest for {ext_name}: {e}")
                continue

            # Store the extension info
            self.loaded_extensions[ext_name] = {
                'path': ext_path,
                'manifest': manifest,
                'id': ext_name
            }


    
    def update_extension_buttons(self):
        """Scans for extensions and adds a button for each one with a popup to the main toolbar."""
        # Remove previous extension buttons
        for action in self.extension_actions:
            self.toolbar.removeAction(action)
        self.extension_actions.clear()

        if not self.extensions_dir or not os.path.exists(self.extensions_dir):
            return

        self.update_extensions_list()

        for ext_name in self.loaded_extensions.keys():
            manifest = self.loaded_extensions[ext_name]['manifest']
            ext_path = self.loaded_extensions[ext_name]['path']

            # Check for a popup action
            popup_path = None
            action = manifest.get('action') or manifest.get('browser_action') or manifest.get('page_action')
            if action and action.get('default_popup'):
                popup_path = action.get('default_popup')

            if popup_path:
                # Create a button for this extension
                button = QPushButton()
                button.setFlat(True)
                button.setIconSize(QSize(22, 22))

                # Set the icon
                icon_path = None
                if manifest.get("icons"):
                    # Prefer a 24px or 16px icon for the toolbar
                    icon_path = manifest["icons"].get("24") or manifest["icons"].get("16") or next(iter(manifest["icons"].values()), None)
                
                if icon_path:
                    full_icon_path = os.path.join(ext_path, icon_path)
                    if os.path.exists(full_icon_path):
                        button.setIcon(QIcon(full_icon_path))
                
                button.setToolTip(manifest.get("name", ext_name))
                
                button.clicked.connect(partial(self.open_extension_popup_from_toolbar, ext_path))
                
                # Insert the button before the main "Extensions" button
                action = self.toolbar.insertWidget(self.extensions_button_action, button)
                self.extension_actions.append(action)


    def launch_test_extension(self):
        """Launch the test extension in a new tab."""
        # Check if the test extension is loaded
        print(self.loaded_extensions)
        if 'test-extension' not in self.loaded_extensions:
            QMessageBox.warning(self, "Extension Not Found",
                               "The test extension was not found. Make sure it's in the assets/browser/extensions directory.")
            return
        
        ext_info = self.loaded_extensions['test-extension']
        
        # First, launch the background page to ensure the background script is running
        self.launch_extension_background('test-extension')
        
        # Then open the popup in a new tab
        manifest = ext_info['manifest']
        popup_path = None
        
        # Check for popup in the manifest
        action = manifest.get('action') or manifest.get('browser_action') or manifest.get('page_action')
        if action and action.get('default_popup'):
            popup_path = action.get('default_popup')
        
        if popup_path:
            # Create a URL for the popup
            popup_url = f"qextension://test-extension/{popup_path}"
            
            # Open in a new tab
            tab = self.new_page(popup_url)
            self.tabs.setTabText(self.tabs.indexOf(tab), f"Test Extension: {manifest.get('name', 'Popup')}")
            
            print(f"Launched test extension popup: {popup_url}")
        else:
            QMessageBox.warning(self, "No Popup", "The test extension does not have a popup defined in its manifest.")
    
    def launch_extension_background(self, extension_id):
        """Launch an extension's background page or script in a hidden tab."""
        print(self.loaded_extensions)
        if extension_id not in self.loaded_extensions:
            print(f"Extension {extension_id} not found")
            return None
        
        ext_info = self.loaded_extensions[extension_id]
        manifest = ext_info['manifest']
        
        # Check for background page or script
        background = manifest.get('background', {})
        background_page = background.get('page')
        background_script = background.get('service_worker')
        
        if background_page:
            # Create a URL for the background page
            bg_url = f"qextension://{extension_id}/{background_page}"
            
            # Open in a new tab (could be hidden in a real implementation)
            tab = self.new_page(bg_url)
            self.tabs.setTabText(self.tabs.indexOf(tab), f"{extension_id} Background")
            
            # Ensure WebChannel is set up for this tab
            if hasattr(tab, 'web_view') and hasattr(tab.web_view, 'page'):
                page = tab.web_view.page()
                
                # First load QWebChannel.js content
                qwebchannel_path = os.path.join("assets/browser/js", "qwebchannel.js")
                qwebchannel_js = ""
                try:
                    with open(qwebchannel_path, 'r', encoding='utf-8') as f:
                        qwebchannel_js = f.read()
                except Exception as e:
                    print(f"Error loading QWebChannel.js: {e}")
                    qwebchannel_js = "console.error('Failed to load QWebChannel.js');"
                
                # Explicitly initialize the QWebChannel with a script that includes QWebChannel.js
                init_script = f"""
                    // Directly inject QWebChannel.js content
                    {qwebchannel_js}
                    
                    console.log("QWebChannel.js directly injected into background page");
                    
                    // Verify QWebChannel is defined
                    if (typeof QWebChannel === 'undefined') {{
                        console.error("QWebChannel is still undefined after direct injection!");
                    }} else {{
                        console.log("QWebChannel is successfully defined in global scope");
                    }}
                    
                    // Create a global variable to track if transport is ready
                    window.__qtWebChannelTransportReady = false;
                    
                    function initializeWebChannel() {{
                        if (typeof qt !== 'undefined' && qt.webChannelTransport) {{
                            try {{
                                // QWebChannel should be defined now
                                new QWebChannel(qt.webChannelTransport, function(channel) {{
                                    window.channel = channel;
                                    window.runtimeBridge = channel.objects.runtimeBridge;
                                    window.__qtWebChannelTransportReady = true;
                                    console.log("QWebChannel initialized successfully for background page");
                                    
                                    // Dispatch an event to notify that the channel is ready
                                    document.dispatchEvent(new CustomEvent('webChannelReady', {{
                                        detail: {{ channel: channel }}
                                    }}));
                                    
                                    // Also dispatch the chrome.runtime.initialized event
                                    document.dispatchEvent(new CustomEvent('chrome.runtime.initialized', {{
                                        detail: {{ extensionId: "{extension_id}" }}
                                    }}));
                                    
                                    // Make chrome.runtime available globally
                                    if (window.runtimeBridge) {{
                                        console.log("RuntimeBridge is available, initializing chrome.runtime API");
                                        // Expose chrome.runtime API
                                        if (typeof chrome === 'undefined') {{
                                            window.chrome = {{}};
                                        }}
                                        if (typeof chrome.runtime === 'undefined') {{
                                            chrome.runtime = {{}};
                                        }}
                                        
                                        // Define basic chrome.runtime API methods
                                        chrome.runtime.id = "{extension_id}";
                                        chrome.runtime.sendMessage = function(extensionId, message, options, callback) {{
                                            if (typeof extensionId !== 'string') {{
                                                callback = options;
                                                options = message;
                                                message = extensionId;
                                                extensionId = "{extension_id}";
                                            }}
                                            // Always pass an options parameter, even if it's empty
                                            if (typeof options === 'undefined') {{
                                                options = {{}};
                                            }}
                                            return window.runtimeBridge.sendMessage(extensionId, JSON.stringify(message), JSON.stringify(options));
                                        }};
                                    }}
                                }});
                                return true;
                            }} catch (e) {{
                                console.error("Error initializing QWebChannel:", e);
                                return false;
                            }}
                        }} else {{
                            console.log("qt.webChannelTransport not available yet, will retry later");
                            return false;
                        }}
                    }}
                    
                    // Create a global variable to track initialization attempts
                    window.__qwebchannel_init_attempts = 0;
                    
                    // Try to initialize immediately
                    if (!initializeWebChannel()) {{
                        // If it fails, set up a retry mechanism
                        const MAX_RETRIES = 50;
                        
                        const retryInterval = setInterval(function() {{
                            window.__qwebchannel_init_attempts++;
                            console.log("Retrying QWebChannel initialization... (attempt " + window.__qwebchannel_init_attempts + " of " + MAX_RETRIES + ")");
                            
                            // Check if qt object exists, if not, try to create it
                            if (typeof qt === 'undefined') {{
                                console.log("qt object is undefined, creating placeholder");
                                window.qt = {{}};
                            }}
                            
                            if (initializeWebChannel() || window.__qwebchannel_init_attempts >= MAX_RETRIES) {{
                                clearInterval(retryInterval);
                                if (window.__qwebchannel_init_attempts >= MAX_RETRIES) {{
                                    console.error("Failed to initialize QWebChannel after " + MAX_RETRIES + " attempts");
                                }}
                            }}
                        }}, 200);
                    }}
                """
                
                # Run the initialization script
                page.runJavaScript(init_script, lambda result: print("QWebChannel initialization script executed for background page"))
            
            print(f"Launched extension background page: {bg_url}")
            return tab
        elif background_script:
            # For service workers, we need to create a special page that loads the script
            # This is a simplified approach - in a real implementation, you'd use a proper service worker container
            
            # Create a temporary HTML file that loads the background script
            temp_dir = os.path.join(self.profile_dir, "temp")
            os.makedirs(temp_dir, exist_ok=True)
            
            # Include WebChannel initialization in the HTML file
            temp_html_path = os.path.join(temp_dir, f"{extension_id}_background.html")
            with open(temp_html_path, 'w', encoding='utf-8') as f:
                f.write(f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{extension_id} Background</title>
    <script>
        // Create a global variable to track if transport is ready
        window.__qtWebChannelTransportReady = false;
        
        function initializeWebChannel() {{
            if (typeof qt !== 'undefined' && qt.webChannelTransport) {{
                try {{
                    // Check if QWebChannel is defined
                    if (typeof QWebChannel === 'undefined') {{
                        console.log("QWebChannel is not defined yet, will retry later");
                        return false;
                    }}
                    
                    new QWebChannel(qt.webChannelTransport, function(channel) {{
                        window.channel = channel;
                        window.runtimeBridge = channel.objects.runtimeBridge;
                        window.__qtWebChannelTransportReady = true;
                        console.log("QWebChannel initialized successfully for background script");
                        
                        // Dispatch an event to notify that the channel is ready
                        document.dispatchEvent(new CustomEvent('webChannelReady', {{
                            detail: {{ channel: channel }}
                        }}));
                        
                        // Also dispatch the chrome.runtime.initialized event
                        document.dispatchEvent(new CustomEvent('chrome.runtime.initialized', {{
                            detail: {{ extensionId: "{extension_id}" }}
                        }}));
                    }});
                    return true;
                }} catch (e) {{
                    console.error("Error initializing QWebChannel:", e);
                    return false;
                }}
            }} else {{
                console.log("qt.webChannelTransport not available yet, will retry later");
                return false;
            }}
        }}
        
        // Try to initialize immediately
        document.addEventListener('DOMContentLoaded', function() {{
            if (!initializeWebChannel()) {{
                // If it fails, set up a retry mechanism
                let retryCount = 0;
                const MAX_RETRIES = 50;
                
                const retryInterval = setInterval(function() {{
                    console.log("Retrying QWebChannel initialization... (attempt " + (retryCount + 1) + " of " + MAX_RETRIES + ")");
                    if (initializeWebChannel() || retryCount >= MAX_RETRIES) {{
                        clearInterval(retryInterval);
                        if (retryCount >= MAX_RETRIES) {{
                            console.error("Failed to initialize QWebChannel after " + MAX_RETRIES + " attempts");
                        }}
                    }}
                    retryCount++;
                }}, 200);
            }}
        }});
    </script>
</head>
<body>
    <h1>{extension_id} Background Script</h1>
    <p>This page loads the background script for the extension.</p>
    <script src="qextension://{extension_id}/{background_script}"></script>
</body>
</html>""")
            
            # Open the temporary HTML file in a new tab

            tab = self.new_page(f"file://{temp_html_path}")
            self.tabs.setTabText(self.tabs.indexOf(tab), f"{extension_id} Background")
            
            # Ensure WebChannel is set up for this tab
            if hasattr(tab, 'web_view') and hasattr(tab.web_view, 'page'):
                page = tab.web_view.page()
                page.setWebChannel(self.web_channel)
            
            print(f"Launched extension background script: {background_script}")
            return tab
        else:
            print(f"Extension {extension_id} has no background page or script")
            return None
    
    def debug_chrome_urls(self):
        """Debug chrome:// URLs by showing information and testing navigation."""
        debug_dialog = QDialog(self)
        debug_dialog.setWindowTitle("Chrome URL Debug")
        debug_dialog.resize(600, 500)
        
        layout = QVBoxLayout(debug_dialog)
        
        # Add information about the current configuration
        info_text = QTextEdit()
        info_text.setReadOnly(True)
        
        # Collect debug information
        debug_info = [
            "Chrome URL Debug Information:",
            "----------------------------",
            f"Profile Path: {self.profile_dir}",
            f"User Agent: {self.profile.httpUserAgent()}",
            "WebEngine Settings:",
            f"  LocalContentCanAccessRemoteUrls: {self.profile.settings().testAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls)}",
            f"  ErrorPageEnabled: {self.profile.settings().testAttribute(QWebEngineSettings.WebAttribute.ErrorPageEnabled)}",
            f"  FocusOnNavigationEnabled: {self.profile.settings().testAttribute(QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled)}",
            f"  AllowRunningInsecureContent: {self.profile.settings().testAttribute(QWebEngineSettings.WebAttribute.AllowRunningInsecureContent)}",
            "Environment Variables:",
            f"  QTWEBENGINE_CHROMIUM_FLAGS: {os.environ.get('QTWEBENGINE_CHROMIUM_FLAGS', 'Not set')}",
            "----------------------------",
            "Instructions:",
            "1. Click 'Test Chrome URL' to open chrome://version/ in a new tab",
            "2. If it doesn't work, try restarting the browser with --debug flag",
            "3. Check if the custom ChromeWebEnginePage is being used correctly"
        ]
        
        info_text.setText("\n".join(debug_info))
        layout.addWidget(info_text)
        
        # Add buttons for testing
        button_layout = QHBoxLayout()
        
        test_button = QPushButton("Test Chrome URL")
        test_button.clicked.connect(lambda: self.navigate_to_chrome_url("chrome://version/"))
        button_layout.addWidget(test_button)
        
        close_button = QPushButton("Close")
        close_button.clicked.connect(debug_dialog.accept)
        button_layout.addWidget(close_button)
        
        layout.addLayout(button_layout)
        
        debug_dialog.exec()
    
    def show_extensions(self):
        """Show the extensions dialog."""
        dialog = ExtensionDialog(self, self.extensions_dir)
        dialog.exec()





async def main_async():
    """Async main function to run the browser."""
    browser = QPlaywrightBrowser()
    await browser.launch()
    
    # Open a page
    url = "https://www.google.com"
    if len(sys.argv) > 1:
        url = sys.argv[1]
    
    await browser.new_page(url)
    
    # Keep the browser running
    while True:
        await asyncio.sleep(0.1)


def main():
    """Main function to run the browser as a standalone application."""
   
    # Enable Autofill features and extension developer mode via environment variables
    chromium_flags = "--enable-features=AutofillEnableAccountWalletStorage,AutofillAddressProfileSavePrompt,AutofillCreditCardUpload,AutofillEnableToolbarStatusChip,AutofillKeyboardAccessory,AutofillShowAllSuggestionsOnPrefsCheckout,AutofillShowTypePredictions,AutofillUpstream,PasswordGeneration,PasswordGenerationBottomSheetUI,PasswordGenerationExperiment,ExtensionsToolbarMenu,ChromeUIDebugTools --extensions-on-chrome-urls --allow-file-access-from-files --allow-running-insecure-content --enable-user-scripts --allow-universal-access-from-files --disable-web-security --disable-site-isolation-trials --allow-insecure-localhost --ignore-certificate-errors --ignore-urlfetcher-cert-requests --disable-features=BlockInsecurePrivateNetworkRequests"
    
    # Always add extension developer mode flags
    #chromium_flags += " --load-extension=assets/browser/extensions --force-dev-mode-highlighting"
    chromium_flags += " --force-dev-mode-highlighting"

    # Explicitly enable chrome:// URLs
    chromium_flags += " --enable-chrome-urls --enable-features=ChromeUIDebugTools"
    
    # Chrome scheme is already registered in register_url_schemes()
    
    os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = chromium_flags
    
    debug_mode = "--debug" in sys.argv

    #Print environment variables for debugging and set remote debug where needed
    print(f"QTWEBENGINE_CHROMIUM_FLAGS: {os.environ.get('QTWEBENGINE_CHROMIUM_FLAGS')}")
    if debug_mode:
        os.environ["QTWEBENGINE_REMOTE_DEBUGGING"] = "9222"
        print(f"QTWEBENGINE_REMOTE_DEBUGGING: {os.environ.get('QTWEBENGINE_REMOTE_DEBUGGING')}")
        
    app = QApplication.instance() or QApplication(sys.argv)
    
    # Allow Ctrl+C to kill the application gracefully
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    # Set application logo
    app.setWindowIcon(QIcon('assets/logo.jpg'))

    # Set a modern, dark theme
    app.setStyle("Fusion")
    dark_palette = app.palette()
    dark_palette.setColor(dark_palette.ColorRole.Window, QColor(45, 45, 45))
    dark_palette.setColor(dark_palette.ColorRole.WindowText, Qt.GlobalColor.white)
    dark_palette.setColor(dark_palette.ColorRole.Base, QColor(25, 25, 25))
    dark_palette.setColor(dark_palette.ColorRole.AlternateBase, QColor(53, 53, 53))
    dark_palette.setColor(dark_palette.ColorRole.ToolTipBase, QColor(25, 25, 25))
    dark_palette.setColor(dark_palette.ColorRole.ToolTipText, Qt.GlobalColor.white)
    dark_palette.setColor(dark_palette.ColorRole.Text, Qt.GlobalColor.white)
    dark_palette.setColor(dark_palette.ColorRole.Button, QColor(53, 53, 53))
    dark_palette.setColor(dark_palette.ColorRole.ButtonText, Qt.GlobalColor.white)
    dark_palette.setColor(dark_palette.ColorRole.BrightText, Qt.GlobalColor.red)
    dark_palette.setColor(dark_palette.ColorRole.Link, QColor(42, 130, 218))
    dark_palette.setColor(dark_palette.ColorRole.Highlight, QColor(42, 130, 218))
    dark_palette.setColor(dark_palette.ColorRole.HighlightedText, Qt.GlobalColor.black)
    app.setPalette(dark_palette)

    # Set a better font
    font = QFont("Cantarell", 10)
    if platform.system() == "Windows":
        font = QFont("Segoe UI", 10)
    elif platform.system() == "Darwin":
        font = QFont("San Francisco", 10)
    app.setFont(font)

    # Create a dummy parent for dialogs to ensure they are properly modal
    dummy_parent = QWidget()

    # Get profile path
    profile_path = ProfileDialog.get_profile_path(dummy_parent)
    if not profile_path:
        return 0 # Exit gracefully

    # Create a simple browser directly without Playwright for now
    # This ensures we at least get a window showing
    initial_url = None
    if len(sys.argv) > 1 and not sys.argv[1].startswith('--'):
        initial_url = sys.argv[1]

    browser = Browser(initial_url=initial_url, debug=debug_mode, profile_path=profile_path)
    browser.show()
    
    print("Browser window should be visible now")
    
    # Run the Qt event loop
    return app.exec()


# Register schemes before anything else
register_url_schemes()

if __name__ == "__main__":
    sys.exit(main())
