"""Regression tests for ``rich_console`` (Rich layout under non-TTY / TERM=dumb).

These encode expected behavior for wide panels — not a pixel snapshot of the whole
installer, but checks that measurement and ``print_measured_panel`` do not clamp
to ~80 columns when content is long.

Also covers ``make_console`` and ``install._emit_install_banner`` wiring when a
test injects a capture ``Console`` (pedantic path coverage).
"""

from __future__ import annotations

import re
import sys
from io import StringIO
from pathlib import Path

import pytest
from rich.console import Console
from rich.panel import Panel

from mcp_vm_blackbox.install import _emit_install_banner
from mcp_vm_blackbox.rich_console import get_rendered_width, make_console, print_measured_panel, stderr_interactive


def test_stderr_interactive_follows_stderr_isatty(monkeypatch: pytest.MonkeyPatch) -> None:
    """``stderr_interactive`` mirrors ``sys.stderr.isatty()`` for ``Progress(disable=...)``."""
    monkeypatch.setattr(sys.stderr, "isatty", lambda: False)
    assert stderr_interactive() is False
    monkeypatch.setattr(sys.stderr, "isatty", lambda: True)
    assert stderr_interactive() is True


def test_get_rendered_width_exceeds_default_narrow_cap() -> None:
    """``Measurement`` must see natural panel width, not a ~80 cap from dumb sizing."""
    long_line: str = "x" * 200
    panel = Panel(f"title line\nRepo: {long_line}")
    assert get_rendered_width(panel) > 150


def test_print_measured_panel_preserves_contiguous_long_line() -> None:
    """Printed panel output must contain the full long token (no hard wrap mid-run)."""
    long_line = "y" * 180
    panel = Panel(f"installer\n[dim]Repo: {long_line}[/]")
    buf = StringIO()
    console = Console(file=buf, soft_wrap=True)
    print_measured_panel(console, panel)
    out = buf.getvalue()
    assert re.search(r"y{180}", out), out[:500]


@pytest.mark.parametrize("term", ["dumb", "xterm-256color"])
def test_print_measured_panel_wide_under_various_term(term: str, monkeypatch: pytest.MonkeyPatch) -> None:
    """``TERM=dumb`` used to break width-only fixes; ``console.size`` must still allow wide render."""
    monkeypatch.setenv("TERM", term)
    long_line = "z" * 160
    panel = Panel(f"h\n{long_line}")
    buf = StringIO()
    console = Console(file=buf, soft_wrap=True)
    print_measured_panel(console, panel)
    assert re.search(r"z{160}", buf.getvalue())


@pytest.mark.parametrize(
    ("stderr", "patch_stream", "is_tty", "expect_soft_wrap"),
    [
        (False, "stdout", True, False),
        (False, "stdout", False, True),
        (True, "stderr", True, False),
        (True, "stderr", False, True),
    ],
)
def test_make_console_soft_wrap_tracks_target_stream(
    stderr: bool, patch_stream: str, is_tty: bool, expect_soft_wrap: bool, monkeypatch: pytest.MonkeyPatch
) -> None:
    """``make_console`` must read ``isatty`` on the stream Rich will use (stdout vs stderr)."""
    stream = getattr(sys, patch_stream)

    def _isatty() -> bool:
        return is_tty

    monkeypatch.setattr(stream, "isatty", _isatty)
    c = make_console(stderr=stderr)
    assert c.soft_wrap is expect_soft_wrap


def test_emit_install_banner_tty_uses_plain_print(monkeypatch: pytest.MonkeyPatch) -> None:
    """When ``stdout.isatty()``, banner uses ``console.print`` (not measured panel)."""
    monkeypatch.setattr(sys.stdout, "isatty", lambda: True)
    buf = StringIO()
    cap = Console(file=buf, soft_wrap=False)
    _emit_install_banner(Path("/tmp/repo"), banner_console=cap)
    out = buf.getvalue()
    assert "vm-flightsimulator installer" in out
    assert "/tmp/repo" in out


def test_emit_install_banner_non_tty_preserves_long_repo_path(monkeypatch: pytest.MonkeyPatch) -> None:
    """Piped stdout: measured panel must not hard-wrap a long ``repo_root`` string."""
    monkeypatch.setattr(sys.stdout, "isatty", lambda: False)
    buf = StringIO()
    cap = Console(file=buf, soft_wrap=True)
    marker = "M" * 130
    _emit_install_banner(Path("/tmp") / marker, banner_console=cap)
    assert re.search(r"M{130}", buf.getvalue()), buf.getvalue()[:400]
