"""Tests for daemon spawn with model override transmission.

Spec source: spawn-result-persistence.spawn-result-persistence-gate-fix
Verifies that --model flag is properly passed through daemon subprocess chain.
"""

import json
import os
import subprocess
import sys
import time
from pathlib import Path


TERMINAL_STATES = {"completed", "failed", "killed"}


def _anima_cmd(*args: str) -> list[str]:
    return [sys.executable, "-m", "anima", *args]


def _write_persona(path: Path, *, name: str, model: str = "test") -> None:
    path.write_text(
        json.dumps(
            {
                "spec_version": "0.1.0",
                "name": name,
                "prompt": "You are a test agent.",
                "model": model,
            }
        )
    )


def _spawn_and_parse(
    *,
    task: str,
    persona_file: Path,
    anima_state: Path,
    extra_env: dict[str, str] | None = None,
) -> tuple[subprocess.CompletedProcess[str], dict[str, object]]:
    short_state = Path("/tmp") / f"anima_state_{os.getpid()}_{time.monotonic_ns()}"
    short_state.symlink_to(anima_state, target_is_directory=True)

    env = os.environ.copy()
    env["ANIMA_STATE"] = str(short_state)
    env["HOME"] = str(anima_state.parent)
    if extra_env:
        env.update(extra_env)

    result = subprocess.run(
        _anima_cmd(
            "spawn",
            task,
            "--persona-file",
            str(persona_file),
            "--model",
            "test",
            "--json",
        ),
        capture_output=True,
        text=True,
        timeout=10,
        env=env,
        check=False,
    )
    assert result.returncode == 0, (
        f"spawn failed rc={result.returncode}\nstdout={result.stdout}\nstderr={result.stderr}"
    )
    try:
        payload = json.loads(result.stdout)
    except json.JSONDecodeError as exc:
        raise AssertionError(
            f"spawn output was not valid JSON:\n{result.stdout}\n{result.stderr}"
        ) from exc
    assert isinstance(payload, dict), f"Expected JSON object payload, got: {payload!r}"
    assert isinstance(payload.get("instance_id"), str) and payload["instance_id"], (
        f"Missing instance_id in spawn output: {payload!r}"
    )
    return result, payload


def _poll_terminal_state(
    state_file: Path, timeout_seconds: float = 10.0
) -> dict[str, object]:
    deadline = time.monotonic() + timeout_seconds
    last_state: dict[str, object] | None = None

    while time.monotonic() < deadline:
        if state_file.exists():
            loaded = json.loads(state_file.read_text())
            if isinstance(loaded, dict):
                last_state = loaded
                if loaded.get("state") in TERMINAL_STATES:
                    return loaded
        time.sleep(0.1)

    raise AssertionError(
        f"state.json did not reach terminal state within {timeout_seconds:.1f}s: "
        f"last={last_state!r}, file={state_file}"
    )


def test_spawn_model_override_completes_successfully(
    tmp_state_dir: Path, tmp_path: Path
) -> None:
    """Daemon spawn with --model test reaches completed state (not failed).

    Verifies that model_override is properly passed through the subprocess chain:
    spawn_impl --model test → agent_runner.py → run_agent_sync → AgentRunner
    """
    persona_file = tmp_path / "persona_model_override.json"
    _write_persona(persona_file, name="spawn-model-override")

    _, payload = _spawn_and_parse(
        task="Test model override transmission",
        persona_file=persona_file,
        anima_state=tmp_state_dir,
    )

    instance_id = str(payload["instance_id"])
    state_file = tmp_state_dir / "agents" / instance_id / "state.json"
    terminal = _poll_terminal_state(state_file, timeout_seconds=10.0)

    # CRITICAL: Must be completed, not failed
    assert terminal.get("state") == "completed", (
        f"Expected completed state, got {terminal.get('state')!r} with error={terminal.get('error')!r} "
        f"for instance {instance_id}"
    )

    # Verify no error field
    assert terminal.get("error") is None, (
        f"Expected no error in completed state, got: {terminal.get('error')!r}"
    )


def test_spawn_model_override_emits_response_events(
    tmp_state_dir: Path, tmp_path: Path
) -> None:
    """Daemon spawn with model=test emits response events for talk replay.

    Verifies that the daemon path produces response events that can be replayed
    via anima talk history.
    """
    persona_file = tmp_path / "persona_response_events.json"
    _write_persona(persona_file, name="spawn-response-events")

    _, payload = _spawn_and_parse(
        task="Test response event emission",
        persona_file=persona_file,
        anima_state=tmp_state_dir,
    )

    instance_id = str(payload["instance_id"])
    state_file = tmp_state_dir / "agents" / instance_id / "state.json"
    terminal = _poll_terminal_state(state_file, timeout_seconds=10.0)

    assert terminal.get("state") == "completed", (
        f"Expected completed, got {terminal.get('state')!r}"
    )

    # Verify log.jsonl exists and contains response events
    log_file = tmp_state_dir / "agents" / instance_id / "log.jsonl"
    assert log_file.exists(), f"log.jsonl missing for instance {instance_id}"

    log_entries = [
        json.loads(line) for line in log_file.read_text().splitlines() if line.strip()
    ]
    response_events = [e for e in log_entries if e.get("event") == "response"]

    assert response_events, (
        f"Expected at least one response event in log.jsonl, got {len(log_entries)} total events"
    )

    # Verify response event structure
    for event in response_events:
        assert "turn_number" in event.get("details", {}), (
            f"Response event missing turn_number: {event!r}"
        )
        assert "response_text" in event.get("details", {}), (
            f"Response event missing response_text: {event!r}"
        )
