import sys
import logging
import warnings
from PyQt6.QtCore import QUrl, QTimer, pyqtSlot
from PyQt6.QtWidgets import QApplication, QMainWindow, QToolBar, QLineEdit, QTabWidget, QLabel, QPushButton
from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWebEngineWidgets import QWebEngineView

# Suppress warning messages
warnings.filterwarnings("ignore")

# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class Browser(QMainWindow):
    def __init__(self):
        super().__init__()
        self.custom_history = []
        self.current_index = -1
        self.contains_match = self.load_trust_list("TrustFile_IfContains.txt")
        self.exact_match = self.load_trust_list("TrustFile_ExactMatch.txt")
        self.setup_ui()

    def setup_ui(self):
        self.tabs = QTabWidget()
        self.setCentralWidget(self.tabs)
        self.tabs.setDocumentMode(True)
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_current_tab)
        self.tabs.currentChanged.connect(self.update_url_bar)  # Update URL when the active tab changes
        self.add_navigation_toolbar()
        self.status_label = QLabel("")
        self.statusBar().addWidget(self.status_label)
        self.add_new_tab(QUrl("file:///C:/KSB/KidSafeBrowserHome.html"), "Homepage")
        self.setWindowTitle("Kid Safe Web Browser")
        self.setWindowIcon(QIcon("KSB-Transp.ico"))  # Set the window icon
        self.show()

    def add_navigation_toolbar(self):
        navtb = QToolBar("Navigation")
        self.addToolBar(navtb)
        navtb.addWidget(self.create_nav_button("Back", self.navigate_back))
        navtb.addWidget(self.create_nav_button("Forward", self.navigate_forward))
        navtb.addAction(self.create_action("Reload", lambda: self.tabs.currentWidget().reload()))
        navtb.addAction(self.create_action("Home", self.navigate_home))
        self.url_bar = QLineEdit()
        self.url_bar.returnPressed.connect(self.navigate_to_url)
        navtb.addWidget(self.url_bar)

    def create_nav_button(self, title, func):
        button = QPushButton(title)
        button.clicked.connect(func)
        return button

    def create_action(self, title, func):
        action = QAction(title, self)
        action.triggered.connect(func)
        return action

    def load_trust_list(self, file_path):
        try:
            with open(file_path, 'r') as file:
                return set(line.strip() for line in file if line.strip())
        except FileNotFoundError:
            logging.warning(f"Trust file '{file_path}' not found.")
            return set()

    def add_new_tab(self, qurl=None, label="Blank"):
        if qurl is None:
            qurl = QUrl('')
        browser = CustomWebEngineView(self, self.contains_match, self.exact_match, self.status_label, self.url_bar)
        browser.setUrl(qurl)
        browser.urlChanged.connect(self.update_url_bar)  # Connect URL change signal
        i = self.tabs.addTab(browser, label)
        self.tabs.setCurrentIndex(i)

    def close_current_tab(self, i):
        if self.tabs.count() < 2:
            return
        self.tabs.removeTab(i)

    def navigate_home(self):
        self.navigate_to(QUrl("file:///C:/KSB/KidSafeBrowserHome.html"))

    def navigate_to_url(self):
        self.navigate_to(QUrl(self.url_bar.text()))

    def navigate_to(self, qurl):
        if self.tabs.currentWidget():
            self.tabs.currentWidget().setUrl(qurl)

    def navigate_back(self):
        if self.current_index > 0:
            self.current_index -= 1
            self.navigate_to(QUrl(self.custom_history[self.current_index]))

    def navigate_forward(self):
        if self.current_index < len(self.custom_history) - 1:
            self.current_index += 1
            self.navigate_to(QUrl(self.custom_history[self.current_index]))

    def update_history(self, qurl):
        url = qurl.toString()
        if any(trusted_part in url for trusted_part in self.contains_match) or url in self.exact_match:
            if self.current_index == -1 or (url != self.custom_history[self.current_index]):
                self.custom_history.append(url)
                self.current_index += 1
                logging.info("Custom History Updated: " + str(self.custom_history))

    @pyqtSlot()
    def update_url_bar(self):
        """Update the URL bar when the URL changes."""
        current_browser = self.tabs.currentWidget()
        if current_browser:
            current_url = current_browser.url().toString()
            self.url_bar.setText(current_url)

class CustomWebEngineView(QWebEngineView):
    def __init__(self, main_window, contains_match, exact_match, status_label, url_bar):
        super().__init__()
        self.main_window = main_window
        self.contains_match = contains_match
        self.exact_match = exact_match
        self.status_label = status_label
        self.url_bar = url_bar
        self.loadFinished.connect(self.on_load_finished)
        self.urlChanged.connect(self.on_url_changed)
        self.page().linkHovered.connect(self.on_link_hovered)

    def on_url_changed(self, qurl):
        url = qurl.toString()
        if any(trusted_part in url for trusted_part in self.contains_match) or url in self.exact_match:
            self.main_window.update_history(qurl)
        else:
            logging.error(f"URL not trusted: {url}. Redirecting to warning page.")
            self.display_warning_page()

    def on_link_hovered(self, link):
        if link:
            self.status_label.setText(f"Hovered over link: {link}")
        else:
            self.status_label.setText("")

    def display_warning_page(self):
        warning_url = QUrl("file:///C:/KSB/Warning-UnSafe-Site.html")
        self.setUrl(warning_url)
        QTimer.singleShot(100, lambda: self.url_bar.setText(warning_url.toString()))
        logging.info("Navigated to warning page due to untrusted URL.")

    def acceptNavigationRequest(self, qurl, _type, isMainFrame):
        url = qurl.toString()
        if url not in self.contains_match and url not in self.exact_match:
            self.display_warning_page()
            return False
        return super().acceptNavigationRequest(qurl, _type, isMainFrame)

    def on_load_finished(self, success):
        if not success:
            logging.error("Page failed to load.")
        else:
            logging.info("Page loaded successfully.")

def handle_unexpected_exceptions(exc_type, exc_value, exc_traceback):
    logging.critical("An unexpected error occurred:", exc_info=(exc_type, exc_value, exc_traceback))

if __name__ == "__main__":
    sys.excepthook = handle_unexpected_exceptions
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    window = Browser()
    window.show()
    sys.exit(app.exec())
