import os
import stat

import pytest

pytest.importorskip("tkinter")

from ccma.config import AppConfig  # noqa: E402
from ccma.storage.repository import MemberRepository  # noqa: E402

# Root ignores the permission bits that stand in for a read-only mount here.
pytestmark = pytest.mark.skipif(
    hasattr(os, "geteuid") and os.geteuid() == 0, reason="root bypasses file permissions"
)


def _set_writable(root, writable: bool) -> None:
    for path in sorted(root.rglob("*"), reverse=True) + [root]:
        mode = stat.S_IMODE(path.stat().st_mode)
        path.chmod(mode | stat.S_IWUSR if writable else mode & ~stat.S_IWUSR)


@pytest.fixture
def read_only_window(tk_root, tmp_path):
    from ccma.ui.main_window import MainWindow

    root_path = tmp_path / "store"
    repository = MemberRepository(root_path)
    repository.initialize()
    repository.create_member(first_name="Ada", last_name="Lovelace", birth_date="1990-01-01")
    _set_writable(root_path, False)

    window = MainWindow(tk_root, MemberRepository(root_path), AppConfig(store_path=str(root_path)), [], [])
    window.pack(fill="both", expand=True)
    tk_root.update()
    yield window
    window.destroy()
    tk_root.title("")
    tk_root.update()
    _set_writable(root_path, True)


def test_a_read_only_store_is_marked_everywhere(read_only_window, tk_root):
    assert "NUR LESEN" in tk_root.title()
    assert "NUR LESEN" in read_only_window.store_var.get()
    assert read_only_window.messages.winfo_manager(), "der Warnbanner fehlt"


def test_the_banner_does_not_ask_for_a_restart(read_only_window):
    banner = read_only_window.messages.winfo_children()[0]
    text = " ".join(
        str(child.cget("text"))
        for child in banner.winfo_children()[0].winfo_children()
        if "text" in child.keys()
    )
    # The banner used to end with "und CCMA neu starten", which is wrong -- the
    # session recovers in place.
    assert "Erneut prüfen" in text
    assert "neu starten" not in text.casefold()
    assert "Neustart ist dafür nicht nötig" in text


def test_a_remounted_store_clears_every_read_only_marker(read_only_window, tk_root, monkeypatch):
    from tkinter import messagebox

    _set_writable(read_only_window.repository.root, True)
    asked = []
    monkeypatch.setattr(
        messagebox, "askyesno", lambda *args, **kwargs: asked.append(args) or False
    )

    read_only_window._recheck_store_access()
    tk_root.update()

    assert read_only_window.repository.read_only is False
    assert "NUR LESEN" not in tk_root.title()
    assert "NUR LESEN" not in read_only_window.store_var.get()
    assert not read_only_window.messages.winfo_manager(), "der Warnbanner steht noch"
    assert read_only_window.status_var.get() == "Der Store ist wieder beschreibbar."
    assert asked, "der übersprungene Hausmeisterlauf wird nicht angeboten"


def test_the_skipped_housekeeper_run_can_be_started_right_away(
    read_only_window, tk_root, monkeypatch
):
    from tkinter import messagebox

    _set_writable(read_only_window.repository.root, True)
    monkeypatch.setattr(messagebox, "askyesno", lambda *args, **kwargs: True)

    read_only_window._recheck_store_access()
    tk_root.update()

    assert (read_only_window.repository.root / "housekeeper.json").is_file()
    assert read_only_window.status_var.get().startswith("Hausmeisterlauf beendet")


def test_a_store_that_is_still_read_only_keeps_its_markers(read_only_window, tk_root):
    read_only_window._recheck_store_access()
    tk_root.update()

    assert "NUR LESEN" in tk_root.title()
    assert "NUR LESEN" in read_only_window.store_var.get()
    assert read_only_window.messages.winfo_manager()
    assert read_only_window.status_var.get() == "Der Store ist weiterhin schreibgeschützt."
