"""Pytest configuration and fixtures for Teams Phone CLI tests."""

# Set terminal environment BEFORE any imports to ensure Rich/Typer see them.
# Rich checks COLUMNS env var and shutil.get_terminal_size() for terminal width.
# In CI environments without a TTY, these can return unusable values.
# NO_COLOR=1 disables ANSI color codes so string matching in tests works correctly.
# (Rich splits "--json" into "-" + "-json" with color codes between, breaking asserts)
import os

os.environ.setdefault("COLUMNS", "120")
os.environ.setdefault("LINES", "24")
os.environ.setdefault("TERM", "xterm-256color")
os.environ["NO_COLOR"] = (
    "1"  # Must be set, not setdefault, to override any existing value
)

# Configure Typer's Rich console BEFORE any Typer imports
# This is critical for CI environments where Rich cannot detect terminal size
import typer.rich_utils as rich_utils

rich_utils._TERMINAL_WIDTH = 120
rich_utils.MAX_WIDTH = 120

import shutil  # noqa: E402
from typing import Any  # noqa: E402
from unittest.mock import MagicMock  # noqa: E402

import pytest  # noqa: E402
from typer import Typer  # noqa: E402
from typer.testing import CliRunner as TyperCliRunner  # noqa: E402
from typer.testing import Result  # noqa: E402

# Store original function for potential restoration
_original_get_terminal_size = shutil.get_terminal_size


def _fixed_terminal_size(fallback: tuple[int, int] = (80, 24)) -> os.terminal_size:
    """Return a fixed terminal size for consistent test behavior."""
    return os.terminal_size((120, 24))


# Patch at module level to catch early imports
shutil.get_terminal_size = _fixed_terminal_size


import re  # noqa: E402


def strip_ansi(text: str) -> str:
    """Remove ANSI escape codes from text for reliable assertion matching."""
    ansi_pattern = re.compile(r"\x1b\[[0-9;]*m")
    return ansi_pattern.sub("", text)


class CliRunnerResult:
    """Wrapper for CliRunner Result that provides ANSI-stripped output.

    In CI environments, Rich may insert ANSI codes that split up text
    (e.g., "--json" becomes "-" + colored "-json"), breaking assertions.
    This wrapper provides `plain_stdout` and `plain_stderr` for reliable matching.
    """

    def __init__(self, result: Result) -> None:
        self._result = result

    def __getattr__(self, name: str) -> Any:
        return getattr(self._result, name)

    @property
    def plain_stdout(self) -> str:
        """Return stdout with ANSI codes stripped."""
        return strip_ansi(self._result.stdout)

    @property
    def plain_stderr(self) -> str:
        """Return stderr with ANSI codes stripped."""
        return strip_ansi(self._result.stderr) if self._result.stderr else ""


class CliRunner(TyperCliRunner):
    """Custom CliRunner that ensures consistent output for tests.

    Wraps results in CliRunnerResult for ANSI-stripped output properties.
    """

    def invoke(
        self,
        app: Typer,
        args: list[str] | str | None = None,
        **kwargs: Any,
    ) -> CliRunnerResult:
        """Invoke the CLI app and wrap the result."""
        kwargs.setdefault("terminal_width", 120)
        result = super().invoke(app, args, **kwargs)
        return CliRunnerResult(result)


def pytest_configure(config: pytest.Config) -> None:
    """Register custom markers for test categorization."""
    config.addinivalue_line("markers", "unit: Fast unit tests with mocks")
    config.addinivalue_line("markers", "integration: Integration tests with real API")
    config.addinivalue_line("markers", "contract: API contract validation tests")


# =============================================================================
# Shared Fixtures
# =============================================================================


@pytest.fixture
def mock_graph_client() -> MagicMock:
    """Create a mock GraphClient for testing.

    Returns a basic MagicMock. Test classes that need specialized behavior
    (e.g., mocked get_paginated responses) should define their own fixture
    to override this one.
    """
    return MagicMock()
