import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QLineEdit, QToolBar, QPushButton, QVBoxLayout, QWidget
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWebEngineCore import QWebEnginePage, QWebEngineProfile, QWebEngineScript
from PySide6.QtCore import QUrl, Qt, QObject, Slot, QFile, QIODevice
from PySide6.QtWebChannel import QWebChannel
import json
import os
import pkg_resources

class ChromeRuntimeBridge(QObject):
    """Emulates a subset of chrome.runtime API for communication."""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.listeners = {}

    @Slot(str, result=str)
    def sendMessage(self, message):
        """Simulate chrome.runtime.sendMessage."""
        print(f"Received message from webpage: {message}")
        response = {"status": "Message received", "data": message}
        return json.dumps(response)

    @Slot(str)
    def addListener(self, callback_id):
        """Simulate chrome.runtime.onMessage.addListener."""
        self.listeners[callback_id] = True
        print(f"Listener added with ID: {callback_id}")

class WebEnginePage(QWebEnginePage):
    """Custom QWebEnginePage to inject chrome.runtime emulation."""
    def __init__(self, profile, parent=None):
        super().__init__(profile, parent)
        self.runtime_bridge = ChromeRuntimeBridge(self)
        self.channel = QWebChannel(self)
        self.setWebChannel(self.channel)
        self.channel.registerObject("runtimeBridge", self.runtime_bridge)

        # Inject QWebChannel.js and chrome.runtime emulation
        self.inject_qwebchannel()
        self.inject_chrome_runtime()

    def inject_qwebchannel(self):
        """Inject qwebchannel.js from Qt installation."""
        # User-configurable path to qwebchannel.js (update this if needed)
        #custom_qwebchannel_path = None  # e.g., "/path/to/qwebchannel.js"
        custom_qwebchannel_path = "/home/nextime/shmcamstudio/assets/browser/js/qwebchannel.js"

        # Try to find qwebchannel.js
        possible_paths = [
            custom_qwebchannel_path,
            pkg_resources.resource_filename('PySide6', 'Qt/libexec/qwebchannel.js') if custom_qwebchannel_path is None else None,
            "/usr/lib64/qt6/libexec/qwebchannel.js",  # Linux fallback
            "/usr/lib/qt6/libexec/qwebchannel.js",    # Alternative Linux path
            "/usr/local/Cellar/qt/6.x.x/libexec/qwebchannel.js"  # macOS Homebrew
        ]

        js_file_path = None
        for path in [p for p in possible_paths if p]:
            if os.path.exists(path):
                js_file_path = path
                break

        if js_file_path:
            print(f"Found qwebchannel.js at: {js_file_path}")
            js_file = QFile(js_file_path)
            if js_file.open(QIODevice.ReadOnly):
                script_content = str(js_file.readAll(), 'utf-8')
                js_file.close()

                web_script = QWebEngineScript()
                web_script.setSourceCode(script_content)
                web_script.setName("qwebchannel")
                web_script.setWorldId(QWebEngineScript.MainWorld)
                web_script.setInjectionPoint(QWebEngineScript.DocumentCreation)
                web_script.setRunsOnSubFrames(True)
                self.scripts().insert(web_script)
            else:
                print(f"Warning: Failed to open qwebchannel.js at {js_file_path}")
        else:
            print("Warning: qwebchannel.js not found in any known paths. WebChannel may not work.")

    def inject_chrome_runtime(self):
        """Inject JavaScript to emulate chrome.runtime API."""
        js_content = """
        (function() {
            console.log('chrome_runtime.js injected');
            // Wait for QWebChannel and runtimeBridge to be ready
            function initChromeRuntime() {
                if (window.qt && window.qt.webChannelTransport && typeof QWebChannel !== 'undefined') {
                    new QWebChannel(qt.webChannelTransport, function(channel) {
                        window.runtimeBridge = channel.objects.runtimeBridge;
                        window.chrome = window.chrome || {};
                        window.chrome.runtime = {
                            sendMessage: function(message, callback) {
                                if (window.runtimeBridge) {
                                    window.runtimeBridge.sendMessage(JSON.stringify(message)).then(function(response) {
                                        if (callback) {
                                            callback(JSON.parse(response));
                                        }
                                    });
                                } else {
                                    console.error('runtimeBridge not available');
                                }
                            },
                            onMessage: {
                                addListener: function(callback) {
                                    const callbackId = 'listener_' + Math.random().toString(36).substr(2, 9);
                                    if (window.runtimeBridge) {
                                        window.runtimeBridge.addListener(callbackId);
                                        window[callbackId] = callback;
                                    } else {
                                        console.error('runtimeBridge not available');
                                    }
                                }
                            }
                        };
                        window.chromeRuntimeReady = true;
                        console.log('chrome.runtime initialized');
                    });
                } else {
                    console.log('Waiting for QWebChannel...');
                    setTimeout(initChromeRuntime, 50);
                }
            }
            initChromeRuntime();
        })();
        """

        # Write JS content to a file
        js_file_path = "chrome_runtime.js"
        with open(js_file_path, "w") as f:
            f.write(js_content)

        # Read and inject the JS file
        js_file = QFile(js_file_path)
        if js_file.open(QIODevice.ReadOnly):
            script_content = str(js_file.readAll(), 'utf-8')
            js_file.close()

            web_script = QWebEngineScript()
            web_script.setSourceCode(script_content)
            web_script.setName("chromeRuntimeEmulation")
            web_script.setWorldId(QWebEngineScript.MainWorld)
            web_script.setInjectionPoint(QWebEngineScript.DocumentReady)
            web_script.setRunsOnSubFrames(True)
            self.scripts().insert(web_script)

        # Clean up the JS file
        if os.path.exists(js_file_path):
            os.remove(js_file_path)

class BrowserWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Qt6 Web Browser with chrome.runtime Emulation")
        self.resize(1000, 600)

        # Create WebEngineView
        self.profile = QWebEngineProfile.defaultProfile()
        self.web_view = QWebEngineView()
        self.web_page = WebEnginePage(self.profile, self.web_view)
        self.web_view.setPage(self.web_page)

        # Create URL bar
        self.url_bar = QLineEdit()
        self.url_bar.setPlaceholderText("Enter URL and press Enter")
        self.url_bar.returnPressed.connect(self.load_url)

        # Create navigation toolbar
        toolbar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, toolbar)

        back_btn = QPushButton("Back")
        back_btn.clicked.connect(self.web_view.back)
        toolbar.addWidget(back_btn)

        forward_btn = QPushButton("Forward")
        forward_btn.clicked.connect(self.web_view.forward)
        toolbar.addWidget(forward_btn)

        reload_btn = QPushButton("Reload")
        reload_btn.clicked.connect(self.web_view.reload)
        toolbar.addWidget(reload_btn)

        toolbar.addWidget(self.url_bar)

        # Set up main layout
        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.web_view)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        # Connect URL change signal
        self.web_view.urlChanged.connect(self.update_url_bar)

        # Load a default page with test script
        self.load_test_page()

    def load_url(self):
        url = self.url_bar.text()
        if not url.startswith("http"):
            url = "https://" + url
        self.web_view.setUrl(QUrl(url))

    def update_url_bar(self, qurl):
        self.url_bar.setText(qurl.toString())

    def load_test_page(self):
        """Load a test page with chrome.runtime API usage."""
        html = """
        <!DOCTYPE html>
        <html>
        <head>
            <title>Test chrome.runtime</title>
        </head>
        <body>
            <h1>Test chrome.runtime API</h1>
            <button onclick="testSendMessage()">Send Message</button>
            <p id="response">Response will appear here</p>
            <script>
                function initChromeRuntimeTests() {
                    if (window.chrome && window.chrome.runtime && window.chrome.runtime.onMessage && window.runtimeBridge) {
                        console.log('chrome.runtime tests initialized');
                        // Test chrome.runtime.sendMessage
                        window.testSendMessage = function() {
                            chrome.runtime.sendMessage({ greeting: "Hello from webpage!" }, function(response) {
                                document.getElementById('response').innerText = 
                                    'Response: ' + JSON.stringify(response);
                            });
                        };

                        // Test chrome.runtime.onMessage.addListener
                        chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
                            console.log('Received message:', message);
                            sendResponse({ received: true });
                        });
                    } else {
                        console.log('chrome.runtime or runtimeBridge not ready, retrying...');
                        setTimeout(initChromeRuntimeTests, 50);
                    }
                }

                // Wait for chrome.runtime to be ready
                function waitForChromeRuntime() {
                    if (window.chromeRuntimeReady) {
                        initChromeRuntimeTests();
                    } else {
                        console.log('Waiting for chromeRuntimeReady...');
                        setTimeout(waitForChromeRuntime, 50);
                    }
                }
                waitForChromeRuntime();
            </script>
        </body>
        </html>
        """
        self.web_view.setHtml(html, QUrl("http://localhost"))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = BrowserWindow()
    window.show()
    sys.exit(app.exec())
