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
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.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())