# SPDX-FileCopyrightText: 2025 XLeitstelle Planen und Bauen <xleitstelle@gv.hamburg.de>
# SPDX-FileContributor: Tobias Kraft <tobias.kraft@gv.hamburg.de>
#
# SPDX-License-Identifier: EUPL-1.2

import logging

from qgis.core import QgsApplication
from qgis.PyQt.QtCore import QObject, QUrl
from qgis.PyQt.QtGui import QDesktopServices
from qgis.PyQt.QtWebEngineWidgets import (
    QWebEnginePage,
    QWebEngineProfile,
    QWebEngineSettings,
)

from xmas_plugin.util.metadata import PLUGIN_DIR_NAME, PLUGIN_NAME, PLUGIN_VERSION

logger = logging.getLogger(PLUGIN_DIR_NAME)


def build_user_agent(name: str, version: str | None) -> str:
    if not version:
        raise RuntimeError("PLUGIN_VERSION is empty — invalid state")
    return f"{name}/{version}"


# instantiate shared, off-the-record profile once for maximum performance
profile = QWebEngineProfile(PLUGIN_DIR_NAME, parent=QgsApplication.instance())
profile.setHttpCacheType(QWebEngineProfile.MemoryHttpCache)
profile.setHttpCacheMaximumSize(256 * 1024 * 1024)
profile.setPersistentCookiesPolicy(QWebEngineProfile.NoPersistentCookies)
profile.setHttpUserAgent(build_user_agent(PLUGIN_NAME, PLUGIN_VERSION))

# configure settings once
s = QWebEngineSettings.globalSettings()
s.setAttribute(QWebEngineSettings.AutoLoadIconsForPage, False)
s.setAttribute(QWebEngineSettings.ScrollAnimatorEnabled, False)
s.setAttribute(QWebEngineSettings.JavascriptCanAccessClipboard, False)


class XMASPluginPage(QWebEnginePage):
    """Extends QWebEnginePage with sensible defaults and logging.

    - uses a shared off-the-record profile with memory cache
    - adds logging
    - ignores certificate errors to allow self-signed certificates in webapp
    """

    def __init__(self, parent: QObject | None = None) -> None:
        """Initialize the page with the shared profile and connect signals."""
        super().__init__(profile, parent)
        self.loadFinished.connect(self._on_load_finished)
        self.renderProcessTerminated.connect(
            lambda status, code: logger.warning(
                "render process for URL %s terminated with exit code %s: %s",
                self.url().toString(),
                code,
                status,
            )
        )

    def acceptNavigationRequest(self, new_url, _type, isMainFrame):
        """Open clicked links in browser."""
        if _type != QWebEnginePage.NavigationTypeLinkClicked:
            return super().acceptNavigationRequest(new_url, _type, isMainFrame)
        try:
            QDesktopServices.openUrl(QUrl(new_url))
        except Exception:
            pass
        finally:
            return False

    def _on_load_finished(self, ok: bool) -> None:
        if ok:
            return
        logger.error(
            "failed loading URL %r",
            self.url().toString(),
        )

    def certificateError(self, certificateError) -> bool:
        """Log, but ignore SSL certificate errors."""
        logger.warning("Certificate error: %r", certificateError)
        return True

    def javaScriptConsoleMessage(self, level, message, lineNumber, sourceID) -> None:
        """Log js console message according to severity level."""
        # filter out spammy, but irrelevant message
        if "ResizeObserver loop limit exceeded" in message:
            return
        log_level = {0: "debug", 1: "warning", 2: "error"}
        getattr(logger, log_level.get(level, "error"))(
            "[JS] %s:%s: %r", sourceID, lineNumber, message
        )
