"""Debug screenshot viewer — shows a live screenshot on top of ALL windows.

Used to test whether CSCA/SEB blocks mss screen capture.
Triggered via tray menu: "Debug: Screenshot Test".

The window intentionally does NOT apply WDA_EXCLUDEFROMCAPTURE so that
the captured image is visible. Uses extreme Z-order techniques to stay
above CSCA kiosk windows.
"""

from __future__ import annotations

import ctypes
import logging
import sys
import threading
from datetime import datetime

from PyQt6.QtCore import Qt, QTimer, pyqtSignal
from PyQt6.QtGui import QImage, QPixmap, QFont, QColor
from PyQt6.QtWidgets import (
    QApplication,
    QLabel,
    QVBoxLayout,
    QHBoxLayout,
    QPushButton,
    QWidget,
)

log = logging.getLogger(__name__)

# Windows constants
_HWND_TOPMOST = -1
_SWP_NOMOVE = 0x0002
_SWP_NOSIZE = 0x0001
_SWP_NOACTIVATE = 0x0010
_GWL_EXSTYLE = -20
_WS_EX_TOPMOST = 0x00000008
_WS_EX_TOOLWINDOW = 0x00000080
_WS_EX_LAYERED = 0x00080000
_WS_EX_NOACTIVATE = 0x08000000

_STYLE = """
QWidget#debug_root {
    background-color: rgba(10, 10, 10, 245);
    border: 2px solid #ff4444;
    border-radius: 6px;
}
QLabel#title_label {
    color: #ff4444;
    font-size: 13px;
    font-weight: bold;
    padding: 4px 8px;
}
QLabel#info_label {
    color: #aaaaaa;
    font-size: 11px;
    padding: 2px 8px;
}
QLabel#screenshot_label {
    border: 1px solid #333;
    background-color: #111;
}
QPushButton {
    background-color: #333;
    color: #eee;
    border: 1px solid #555;
    border-radius: 4px;
    padding: 4px 12px;
    font-size: 11px;
}
QPushButton:hover {
    background-color: #444;
}
QPushButton#refresh_btn {
    background-color: #1a4a1a;
    color: #88ff88;
    border-color: #2a7a2a;
}
QPushButton#refresh_btn:hover {
    background-color: #225522;
}
QPushButton#close_btn {
    background-color: #4a1a1a;
    color: #ff8888;
    border-color: #7a2a2a;
}
"""


class DebugScreenshotWindow(QWidget):
    """Floating debug window that captures and displays a screenshot."""

    _update_signal = pyqtSignal(object, str)  # (PIL Image, info_text)

    def __init__(self) -> None:
        super().__init__()
        self._setup_ui()
        self._update_signal.connect(self._apply_screenshot)

        # Re-assert topmost every 50ms (same as overlay)
        self._topmost_timer = QTimer(self)
        self._topmost_timer.timeout.connect(self._assert_topmost)
        self._topmost_timer.start(50)

    def _setup_ui(self) -> None:
        self.setObjectName("debug_root")
        self.setWindowTitle("DEBUG: Screenshot Test")
        self.setWindowFlags(
            Qt.WindowType.FramelessWindowHint
            | Qt.WindowType.WindowStaysOnTopHint
            | Qt.WindowType.Tool
            | Qt.WindowType.WindowDoesNotAcceptFocus
        )
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setAttribute(Qt.WidgetAttribute.WA_ShowWithoutActivating)
        self.setStyleSheet(_STYLE)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(8, 8, 8, 8)
        layout.setSpacing(4)

        # Header
        header_row = QHBoxLayout()
        title = QLabel("🔍 DEBUG: Screenshot Test")
        title.setObjectName("title_label")
        header_row.addWidget(title)
        header_row.addStretch()

        close_btn = QPushButton("✕ Close")
        close_btn.setObjectName("close_btn")
        close_btn.clicked.connect(self.close)
        header_row.addWidget(close_btn)
        layout.addLayout(header_row)

        # Info line
        self._info_label = QLabel("Capturing...")
        self._info_label.setObjectName("info_label")
        self._info_label.setWordWrap(True)
        layout.addWidget(self._info_label)

        # Screenshot display
        self._screenshot_label = QLabel()
        self._screenshot_label.setObjectName("screenshot_label")
        self._screenshot_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self._screenshot_label.setMinimumSize(640, 360)
        self._screenshot_label.setText("Taking screenshot...")
        self._screenshot_label.setStyleSheet("color: #666; font-size: 14px;")
        layout.addWidget(self._screenshot_label)

        # Buttons
        btn_row = QHBoxLayout()
        refresh_btn = QPushButton("🔄 New Screenshot")
        refresh_btn.setObjectName("refresh_btn")
        refresh_btn.clicked.connect(self._take_screenshot_async)
        btn_row.addWidget(refresh_btn)
        btn_row.addStretch()
        layout.addLayout(btn_row)

    def show_centered(self) -> None:
        """Show window centered on primary screen, then take screenshot."""
        screen = QApplication.primaryScreen()
        if screen:
            geom = screen.geometry()
            self.resize(700, 500)
            x = geom.center().x() - self.width() // 2
            y = geom.center().y() - self.height() // 2
            self.move(x, y)
        self.show()
        self.raise_()
        self._apply_win32_topmost()
        # Take screenshot after a short delay so the window is visible first
        QTimer.singleShot(200, self._take_screenshot_async)

    def _take_screenshot_async(self) -> None:
        """Capture screenshot in background thread to not block Qt."""
        self._info_label.setText("Capturing screen...")
        threading.Thread(target=self._do_capture, daemon=True).start()

    def _do_capture(self) -> None:
        """Run in background thread: capture screen and signal the Qt thread."""
        ts = datetime.now().strftime("%H:%M:%S.%f")[:-3]
        try:
            import mss
            from PIL import Image

            with mss.mss() as sct:
                monitors = sct.monitors
                # Capture primary monitor (index 1)
                monitor = monitors[1] if len(monitors) > 1 else monitors[0]
                raw = sct.grab(monitor)
                img = Image.frombytes("RGBA", raw.size, bytes(raw.bgra), "raw", "BGRA")
                img = img.convert("RGB")

                # Check if image is completely black (CSCA blocking)
                extrema = img.convert("L").getextrema()
                is_black = extrema == (0, 0)
                brightness = extrema[1]

                info = (
                    f"[{ts}]  Size: {img.width}×{img.height}  |  "
                    f"Monitor: {monitor['width']}×{monitor['height']}  |  "
                    f"Max brightness: {brightness}  |  "
                    f"{'⚠️ IMAGE IS BLACK — CSCA IS BLOCKING SCREENSHOTS!' if is_black else '✅ Screenshot OK'}"
                )
                self._update_signal.emit(img, info)

        except ImportError:
            self._update_signal.emit(None, f"[{ts}]  ERROR: mss not installed")
        except Exception as exc:
            log.error("Screenshot capture failed: %s", exc)
            self._update_signal.emit(None, f"[{ts}]  ERROR: {exc}")

    def _apply_screenshot(self, img, info_text: str) -> None:
        """Called in Qt thread via signal. Display captured image."""
        self._info_label.setText(info_text)

        if img is None:
            self._screenshot_label.setText("❌ Capture failed — see info above")
            return

        # Convert PIL image → QPixmap
        try:
            data = img.tobytes("raw", "RGB")
            qimage = QImage(data, img.width, img.height, img.width * 3, QImage.Format.Format_RGB888)
            pixmap = QPixmap.fromImage(qimage)

            # Scale to fit label while keeping aspect ratio
            scaled = pixmap.scaled(
                self._screenshot_label.width(),
                self._screenshot_label.height(),
                Qt.AspectRatioMode.KeepAspectRatio,
                Qt.TransformationMode.SmoothTransformation,
            )
            self._screenshot_label.setPixmap(scaled)
        except Exception as exc:
            log.error("Failed to display screenshot: %s", exc)
            self._screenshot_label.setText(f"❌ Display error: {exc}")

    # ------------------------------------------------------------------
    # Z-order: stay on top of CSCA
    # ------------------------------------------------------------------

    def _apply_win32_topmost(self) -> None:
        """Apply aggressive Windows topmost flags — called once on show."""
        if sys.platform != "win32":
            return
        try:
            hwnd = int(self.winId())
            user32 = ctypes.windll.user32  # type: ignore[attr-defined]
            # Force topmost position
            user32.SetWindowPos(
                hwnd, _HWND_TOPMOST, 0, 0, 0, 0,
                _SWP_NOMOVE | _SWP_NOSIZE | _SWP_NOACTIVATE,
            )
            # Extended style: topmost + no taskbar + layered + no activate
            ex_style = _WS_EX_TOPMOST | _WS_EX_TOOLWINDOW | _WS_EX_LAYERED | _WS_EX_NOACTIVATE
            user32.SetWindowLongW(hwnd, _GWL_EXSTYLE, ex_style)
            # NOTE: intentionally NO SetWindowDisplayAffinity here —
            # we WANT this window visible in screenshots for testing.
        except Exception as exc:
            log.warning("Win32 topmost failed: %s", exc)

    def _assert_topmost(self) -> None:
        """Re-assert topmost every 50ms so CSCA can't push us down."""
        if not self.isVisible():
            return
        if sys.platform == "win32":
            try:
                hwnd = int(self.winId())
                user32 = ctypes.windll.user32  # type: ignore[attr-defined]
                user32.SetWindowPos(
                    hwnd, _HWND_TOPMOST, 0, 0, 0, 0,
                    _SWP_NOMOVE | _SWP_NOSIZE | _SWP_NOACTIVATE,
                )
            except Exception:
                pass
        elif sys.platform == "darwin":
            self._assert_topmost_macos()

    def _assert_topmost_macos(self) -> None:
        """Set NSWindowLevel to 1100 — above SEB kiosk level (~1000)."""
        try:
            import ctypes.util
            objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc"))
            objc.objc_getClass.restype = ctypes.c_void_p
            objc.sel_registerName.restype = ctypes.c_void_p
            objc.objc_msgSend.restype = ctypes.c_void_p
            objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

            win_id = int(self.winId())
            nsview = ctypes.c_void_p(win_id)
            sel_window = objc.sel_registerName(b"window")
            nswindow = objc.objc_msgSend(nsview, sel_window)
            if nswindow:
                sel_set_level = objc.sel_registerName(b"setLevel:")
                objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
                objc.objc_msgSend(nswindow, sel_set_level, 1100)
        except Exception:
            pass

    def showEvent(self, event) -> None:
        super().showEvent(event)
        self._apply_win32_topmost()

    def closeEvent(self, event) -> None:
        self._topmost_timer.stop()
        super().closeEvent(event)
