from pathlib import Path
from types import SimpleNamespace

from PyQt6.QtCore import QSettings
from PyQt6.QtWidgets import (
    QApplication,
    QWidget,
)
import pyqtgraph as pg
import pytest
from pytestqt.qtbot import QtBot

from piker import config


@pytest.fixture(scope='module')
def module_qapp(
    qapp: QApplication,

) -> QApplication:
    '''
    Pin pytest-qt's session application for this test module.

    '''
    return qapp


def test_ui_state_is_process_isolated_and_restored(
    isolated_ui_state: SimpleNamespace,
    module_qapp: QApplication,
    pytestconfig: pytest.Config,
    qtbot: QtBot,

) -> None:
    '''
    Prove imports and one UI test cannot reach user config state.

    Previously `qapp_args` assigned `XDG_CONFIG_HOME` only after
    Piker was imported, so `piker.config` cached real user paths
    before Qt setup. This test verifies every cached path starts
    below the process-owned temporary XDG root, then redirects those
    globals and writes both a file and `QSettings` key. The fixture's
    exact-state teardown proves those mutations disappear while its
    process sentinels survive for the next test.

    '''
    state: SimpleNamespace = isolated_ui_state
    assert module_qapp is state.qapp
    assert QApplication.instance() is state.qapp
    if pytestconfig.getoption('headless'):
        assert state.qapp.platformName() == 'offscreen'
    assert config._click_config_dir.is_relative_to(
        state.process_config_home,
    )
    assert config._config_dir.is_relative_to(
        state.process_config_home,
    )
    assert config._watchlists_data_path.is_relative_to(
        state.process_config_home,
    )

    widget: QWidget = QWidget()
    qtbot.addWidget(widget)
    widget.show()

    owned_dir: Path = state.test_config_dir
    config._click_config_dir = owned_dir
    config._config_dir = owned_dir
    config._watchlists_data_path = owned_dir / 'watchlists.json'
    (owned_dir / 'owned').write_text('remove-me', encoding='utf-8')

    settings: QSettings = QSettings('pikers', 'piker')
    settings.setFallbacksEnabled(False)
    settings_path: Path = Path(settings.fileName())
    assert settings_path.is_relative_to(state.process_config_home)
    assert settings.value(state.preexisting_setting) == 'keep-me'
    settings.setValue(state.owned_setting, 'remove-me')
    settings.sync()


def test_ui_state_reuses_qapp_without_previous_test_leaks(
    isolated_ui_state: SimpleNamespace,
    module_qapp: QApplication,
    qtbot: QtBot,

) -> None:
    '''
    Prove repeated tests reuse Qt without inheriting mutable state.

    A session `QApplication` can retain widgets, settings and
    PyQtGraph's `ViewBox.AllViews` entries from an earlier test. This
    test runs after the mutation case, verifies the same application
    and preserved process sentinel but no test-owned key, then
    creates a real named `PlotWidget` and mutates Qt/PyQtGraph
    options. Normal pytest-qt widget closure plus the isolation
    fixture's registry assertions prove the second test also leaves
    no state behind.

    '''
    state: SimpleNamespace = isolated_ui_state
    assert module_qapp is state.qapp
    assert QApplication.instance() is state.qapp

    settings: QSettings = QSettings('pikers', 'piker')
    settings.setFallbacksEnabled(False)
    assert settings.value(state.preexisting_setting) == 'keep-me'
    assert not settings.contains(state.owned_setting)
    assert state.preexisting_config.read_text(
        encoding='utf-8',
    ) == 'keep-me'
    assert list(state.test_config_dir.iterdir()) == []

    plot: pg.PlotWidget = pg.PlotWidget(name='pytest-owned-view')
    qtbot.addWidget(plot)
    plot.show()
    assert pg.ViewBox.NamedViews['pytest-owned-view'] is (
        plot.plotItem.vb
    )

    pg.setConfigOption(
        'antialias',
        not pg.getConfigOption('antialias'),
    )
    state.qapp.setQuitOnLastWindowClosed(
        not state.qapp.quitOnLastWindowClosed(),
    )
