"""conftest.py — pytest configuration and shared fixtures for social-bot tests.

Custom markers:
  @pytest.mark.gpu_required     — skip if no GPU / nvidia-smi
  @pytest.mark.full_stack       — skip unless SOCIAL_TEST_FULL=1
  @pytest.mark.stack_running    — skip unless SOCIAL_STACK_RUNNING=1
  @pytest.mark.slow             — long tests (>30s); skipped in fast mode
  @pytest.mark.launch_test      — launch_testing marker (framework)

Fixtures:
  rclpy_node       — temporary rclpy probe node (auto-shutdown)
  ros_domain_id    — asserts ROS_DOMAIN_ID=108 for test isolation
"""

from __future__ import annotations

import os
import subprocess
import sys
import time

import pytest

# ── Custom markers ────────────────────────────────────────────────────────────


def pytest_configure(config):
    config.addinivalue_line("markers",
        "gpu_required: test requires an NVIDIA GPU (skipped in headless CI)")
    config.addinivalue_line("markers",
        "full_stack: test requires SOCIAL_TEST_FULL=1 (full speech/LLM/TTS)")
    config.addinivalue_line("markers",
        "stack_running: test requires SOCIAL_STACK_RUNNING=1")
    config.addinivalue_line("markers",
        "slow: test takes more than 30 seconds")
    config.addinivalue_line("markers",
        "launch_test: launch_testing integration test")


def pytest_collection_modifyitems(config, items):
    """Automatically skip tests whose markers are not satisfied."""
    full_stack = os.environ.get("SOCIAL_TEST_FULL", "0") == "1"
    stack_running = os.environ.get("SOCIAL_STACK_RUNNING", "0") == "1"
    fast_mode = os.environ.get("CI_FAST", "0") == "1"

    gpu_ok = _nvidia_smi_available()

    for item in items:
        if item.get_closest_marker("gpu_required") and not gpu_ok:
            item.add_marker(pytest.mark.skip(
                reason="No GPU available (set SOCIAL_STACK_RUNNING=1 on hardware)"
            ))
        if item.get_closest_marker("full_stack") and not full_stack:
            item.add_marker(pytest.mark.skip(
                reason="Set SOCIAL_TEST_FULL=1 to enable full-stack tests"
            ))
        if item.get_closest_marker("stack_running") and not stack_running:
            item.add_marker(pytest.mark.skip(
                reason="Set SOCIAL_STACK_RUNNING=1 to enable stack-running tests"
            ))
        if item.get_closest_marker("slow") and fast_mode:
            item.add_marker(pytest.mark.skip(
                reason="Slow test skipped in CI_FAST=1 mode"
            ))


# ── Helpers ───────────────────────────────────────────────────────────────────

def _nvidia_smi_available() -> bool:
    try:
        subprocess.check_output(
            ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
            timeout=5, stderr=subprocess.DEVNULL,
        )
        return True
    except Exception:
        return False


# ── Fixtures ──────────────────────────────────────────────────────────────────

@pytest.fixture(scope="session")
def ros_domain_id():
    """Assert ROS_DOMAIN_ID is set to 108 for test isolation."""
    domain = os.environ.get("ROS_DOMAIN_ID", "0")
    assert domain == "108", (
        f"ROS_DOMAIN_ID must be '108' for isolated test runs (got '{domain}'). "
        "Set: export ROS_DOMAIN_ID=108"
    )
    return int(domain)


@pytest.fixture(scope="function")
def rclpy_node(request):
    """Provide a temporary rclpy probe node; auto-teardown after each test."""
    import rclpy
    if not rclpy.ok():
        rclpy.init()
    node_name = f"test_probe_{request.node.name[:20].replace('/', '_')}"
    node = rclpy.create_node(node_name)
    yield node
    node.destroy_node()


@pytest.fixture(scope="session", autouse=True)
def rclpy_session():
    """Init/shutdown rclpy once for the entire test session."""
    import rclpy
    if not rclpy.ok():
        rclpy.init()
    yield
    if rclpy.ok():
        rclpy.shutdown()
