import subprocess
from pathlib import Path

import pytest

from home_agent.core.config import LoggingConfig
from home_agent.core.logging import configure_logging, reset_logging
from home_agent.utils.subprocess_logging import LoggedSubprocessError, run_logged_subprocess


def test_run_logged_subprocess_logs_preview_only_when_raw_capture_enabled(
    tmp_path: Path,
) -> None:
    configure_logging(
        LoggingConfig(
            directory=tmp_path,
            file_name="test.jsonl",
            console_level="DEBUG",
            file_level="DEBUG",
            enable_console=False,
            capture_raw_payloads=False,
        )
    )

    proc = run_logged_subprocess(
        ["python", "-c", "print('hello world')"],
        logger_name="test.subprocess",
        event="subprocess.test",
    )

    assert proc.stdout.strip() == "hello world"
    joined = (tmp_path / "test.jsonl").read_text(encoding="utf-8")
    assert "subprocess.test.completed" in joined
    assert "hello world" not in joined
    assert '"stdout":' not in joined

    reset_logging()


def test_run_logged_subprocess_logs_raw_output_when_enabled(
    tmp_path: Path,
) -> None:
    configure_logging(
        LoggingConfig(
            directory=tmp_path,
            file_name="test.jsonl",
            console_level="DEBUG",
            file_level="DEBUG",
            enable_console=False,
            capture_raw_payloads=True,
        )
    )

    proc = run_logged_subprocess(
        ["python", "-c", "print('hello world')"],
        logger_name="test.subprocess",
        event="subprocess.test",
    )

    assert proc.stdout.strip() == "hello world"
    joined = (tmp_path / "test.jsonl").read_text(encoding="utf-8")
    assert "subprocess.test.completed" in joined
    assert '"stdout": "hello world\\n"' in joined

    reset_logging()


def test_run_logged_subprocess_raises_logged_error_on_failure(tmp_path: Path) -> None:
    configure_logging(
        LoggingConfig(
            directory=tmp_path,
            file_name="test.jsonl",
            console_level="DEBUG",
            file_level="DEBUG",
            enable_console=False,
            capture_raw_payloads=True,
        )
    )

    with pytest.raises(LoggedSubprocessError) as exc_info:
        run_logged_subprocess(
            [
                "python",
                "-c",
                "import sys; print('bad out'); print('bad err', file=sys.stderr); sys.exit(4)",
            ],
            logger_name="test.subprocess",
            event="subprocess.test",
            check=True,
        )

    assert exc_info.value.returncode == 4
    assert "bad out" in exc_info.value.stdout
    assert "bad err" in exc_info.value.stderr

    reset_logging()


def test_run_logged_subprocess_wraps_timeout_expired(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    configure_logging(
        LoggingConfig(
            directory=tmp_path,
            file_name="test.jsonl",
            console_level="DEBUG",
            file_level="DEBUG",
            enable_console=False,
            capture_raw_payloads=True,
        )
    )

    def fake_run(*args: object, **kwargs: object) -> subprocess.CompletedProcess[str]:
        _ = args, kwargs
        raise subprocess.TimeoutExpired(
            cmd=["python", "-c", "print('slow')"],
            timeout=120,
            output="partial out",
            stderr="partial err",
        )

    monkeypatch.setattr(subprocess, "run", fake_run)

    with pytest.raises(LoggedSubprocessError) as exc_info:
        run_logged_subprocess(
            ["python", "-c", "print('slow')"],
            logger_name="test.subprocess",
            event="subprocess.test",
            check=True,
            timeout=120,
        )

    assert exc_info.value.timeout_seconds == 120
    assert "timed out after 120" in str(exc_info.value)
    assert exc_info.value.stdout == "partial out"
    assert exc_info.value.stderr == "partial err"
    joined = (tmp_path / "test.jsonl").read_text(encoding="utf-8")
    assert "subprocess.test.timeout" in joined

    reset_logging()
