#!/usr/bin/env python3
"""
School Portal LAN Client — with IP prompt before login
"""

import sys, socket, requests
from urllib.parse import urlparse
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtGui


# LAN validation prefix (use your subnet e.g. 192.168. or 10.0.)
ALLOWED_PREFIX = "192.168."
CHECK_TIMEOUT = 3


def get_local_ip_for_target(target_host, target_port=80):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect((target_host, target_port))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return None


def is_server_reachable(url):
    try:
        r = requests.get(url, timeout=CHECK_TIMEOUT)
        return r.status_code < 500
    except:
        return False


class Blocker(QtWebEngineWidgets.QWebEngineUrlRequestInterceptor):
    def __init__(self, allowed_hosts):
        super().__init__()
        self.allowed_hosts = set(h.lower() for h in allowed_hosts)

    def interceptRequest(self, info):
        try:
            host = info.requestUrl().host().lower()
            if not any(host == h or host.endswith("." + h) for h in self.allowed_hosts):
                info.block(True)
        except:
            pass


class PortalPage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, allowed_hosts, parent=None):
        super().__init__(parent)
        self.allowed_hosts = allowed_hosts

    def acceptNavigationRequest(self, url, _type, isMainFrame):
        host = url.host().lower()
        allowed = any(host == h or host.endswith("." + h) for h in self.allowed_hosts)
        if not allowed:
            QtWidgets.QMessageBox.warning(None, "Blocked", f"External site blocked: {host}")
            return False
        return True


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, server_url):
        super().__init__()
        self.server_url = server_url
        host = urlparse(server_url).hostname

        profile = QtWebEngineWidgets.QWebEngineProfile.defaultProfile()
        profile.setRequestInterceptor(Blocker([host]))

        self.view = QtWebEngineWidgets.QWebEngineView()
        self.page = PortalPage([host], self)
        self.view.setPage(self.page)
        self.setCentralWidget(self.view)

        self.setWindowTitle("School Portal")
        self.resize(1200, 800)

        # Toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.addToolBar(self.toolbar)
        self.toolbar.addWidget(QtWidgets.QLabel(server_url))
        reload_btn = QtWidgets.QAction("Reload", self)
        reload_btn.triggered.connect(self.view.reload)
        self.toolbar.addAction(reload_btn)

        self.status = self.statusBar()
        self.exam_mode = False

        # Shortcuts
        QtWidgets.QShortcut(QtGui.QKeySequence("F11"), self, self.fullscreen)
        QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+E"), self, self.toggle_exam)

        self.view.load(QtCore.QUrl(self.server_url))

    def fullscreen(self):
        self.showFullScreen() if not self.isFullScreen() else self.showNormal()

    def toggle_exam(self):
        self.exam_mode = not self.exam_mode
        if self.exam_mode:
            self.toolbar.hide()
            self.showFullScreen()
            self.status.showMessage("Exam Mode Enabled")
        else:
            self.toolbar.show()
            self.showNormal()
            self.status.showMessage("Exam Mode Disabled")


def run_app(server_ip):
    server_url = f"http://{server_ip}/portal/"

    # Check server reachable
    if not is_server_reachable(server_url):
        QtWidgets.QMessageBox.critical(None, "Error", "Server not reachable.")
        return

    # Check LAN only
    local_ip = get_local_ip_for_target(server_ip)
    if not local_ip or not local_ip.startswith(ALLOWED_PREFIX):
        QtWidgets.QMessageBox.critical(None, "Denied", "You are not on the school network.")
        return

    win = MainWindow(server_url)
    win.show()


def main():
    app = QtWidgets.QApplication(sys.argv)

    # Prompt for IP
    ip, ok = QtWidgets.QInputDialog.getText(None, "Enter server IP", "Server IP (e.g 192.168.1.100):")
    if not ok or not ip.strip():
        sys.exit()

    ip = ip.strip()
    run_app(ip)

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
