import os
import logging
import sys

import pytest

os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")

import topovec.cli as root_cli
from topovec.viewer.qt import cli as view_cli

pytest.importorskip("PySide6")

from PySide6 import QtCore, QtGui, QtWidgets
from topovec.viewer.qt import main_window as main_window_mod


def test_build_parser_accepts_view_command_and_flags():
    args = root_cli.build_parser().parse_args(
        ["view", "--debug", "--max-live-scenes", "5", "first.npz", "second.sad"]
    )

    assert args.command == "view"
    assert args.debug is True
    assert args.max_live_scenes == 5
    assert args.paths == ["first.npz", "second.sad"]


def test_main_without_subcommand_prints_help_and_returns_error(capsys):
    code = root_cli.main([])
    captured = capsys.readouterr()

    assert code == 2
    assert "usage: topovec" in captured.err
    assert "view" in captured.err


def test_main_rejects_unknown_subcommand():
    with pytest.raises(SystemExit):
        root_cli.main(["unknown"])


def test_main_rejects_invalid_max_live_scenes():
    with pytest.raises(SystemExit):
        root_cli.main(["view", "--max-live-scenes", "0"])


def test_root_cli_build_parser_does_not_import_gui_modules(monkeypatch):
    monkeypatch.delitem(sys.modules, "topovec.viewer.qt", raising=False)
    monkeypatch.delitem(sys.modules, "topovec.viewer.qt.cli", raising=False)
    monkeypatch.delitem(sys.modules, "topovec.viewer.qt.main_window", raising=False)
    monkeypatch.delitem(sys.modules, "topovec.viewer.qt.viewport", raising=False)
    monkeypatch.delitem(sys.modules, "PySide6", raising=False)

    parser = root_cli.build_parser()

    assert parser.prog == "topovec"
    assert "topovec.viewer.qt.cli" in sys.modules
    assert "topovec.viewer.qt.main_window" not in sys.modules
    assert "topovec.viewer.qt.viewport" not in sys.modules
    assert "PySide6" not in sys.modules


def test_collect_process_environment_includes_prime_and_qt_vars(monkeypatch):
    monkeypatch.setenv("QT_QPA_PLATFORM", "xcb")
    monkeypatch.setenv("__NV_PRIME_RENDER_OFFLOAD", "1")
    monkeypatch.setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia")
    monkeypatch.setenv("DRI_PRIME", "0")

    snapshot = view_cli._collect_process_environment()

    assert snapshot["env"]["QT_QPA_PLATFORM"] == "xcb"
    assert snapshot["env"]["__NV_PRIME_RENDER_OFFLOAD"] == "1"
    assert snapshot["env"]["__GLX_VENDOR_LIBRARY_NAME"] == "nvidia"
    assert snapshot["env"]["DRI_PRIME"] == "0"
    assert snapshot["python"]
    assert snapshot["platform"]


def test_main_logs_startup_failure(monkeypatch):
    messages = []

    class CaptureHandler(logging.Handler):
        def emit(self, record):
            messages.append(record.getMessage())

    logger = logging.getLogger("topovec")
    handler = CaptureHandler()
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)
    logger.propagate = False

    monkeypatch.setattr(view_cli, "configLog", lambda level: logger)
    monkeypatch.setattr(
        view_cli,
        "_load_qt",
        lambda: (_ for _ in ()).throw(RuntimeError("boom")),
    )

    try:
        code = root_cli.main(["view"])
    finally:
        logger.removeHandler(handler)

    assert code == 1
    assert any("Starting topovec view" in message for message in messages)
    assert any("topovec view startup failed" in message for message in messages)


def test_main_opens_only_explicit_startup_paths(monkeypatch):
    app = QtWidgets.QApplication.instance()
    if app is None:
        app = QtWidgets.QApplication([])
    calls = {"load_paths": []}

    class DummyWindow:
        def __init__(self, *, max_live_scenes):
            calls["max_live_scenes"] = max_live_scenes

        def show(self):
            calls["shown"] = True

        def load_paths(self, paths):
            calls["load_paths"].append(list(paths))

    monkeypatch.setattr(view_cli, "_load_qt", lambda: (QtCore, QtGui, QtWidgets))
    monkeypatch.setattr(view_cli, "_log_startup_environment", lambda *_args: None)
    monkeypatch.setattr(main_window_mod, "TvViewWindow", DummyWindow)

    code = root_cli.main(["view", "--max-live-scenes", "3", "first.npz", "second.sad"])

    assert code == 0
    assert calls["shown"] is True
    assert calls["max_live_scenes"] == 3
    assert calls["load_paths"] == [["first.npz", "second.sad"]]
