"""Instant notification tests for approval and suspend control flows.

Spec source: plan step `event-mechanisms`.
"""

import asyncio
from pathlib import Path

import pytest
from returns.result import Success

from anima.core.lifecycle import LifecycleEvent
from anima.core.schemas import AgentState, AgentStateData
from anima.shell.ctl_approval import _wait_for_approval_decision
from anima.shell.state import (
    read_state,
    transition_state,
    write_approval_response,
    write_state,
)


@pytest.fixture
def state_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
    """Configure ANIMA_STATE to a temporary directory."""
    root = tmp_path / "anima_state"
    root.mkdir()
    monkeypatch.setenv("ANIMA_STATE", str(root))
    return root


def _write_state(instance_id: str, state: AgentState) -> None:
    state_data = AgentStateData(
        instance_id=instance_id,
        trace_id=f"tr_{instance_id}",
        persona_name="test",
        state=state,
    )
    write_state(instance_id, state_data)


@pytest.mark.asyncio
async def test_approval_event_instant_notification(state_dir: Path) -> None:
    """Approval wait returns immediately after event notification."""
    _write_state("inst_approval_event", AgentState.awaiting_approval)
    approval_event = asyncio.Event()

    wait_task = asyncio.create_task(
        _wait_for_approval_decision(
            "inst_approval_event",
            poll_interval_seconds=60.0,
            approval_event=approval_event,
        )
    )
    await asyncio.sleep(0.05)
    assert not wait_task.done()

    write_approval_response("inst_approval_event", approved=True, note="approved-now")
    transition_result = transition_state("inst_approval_event", LifecycleEvent.approve)
    assert isinstance(transition_result, Success)

    approval_event.set()
    result = await asyncio.wait_for(wait_task, timeout=0.5)
    assert isinstance(result, Success)
    assert result.unwrap() == {"approved": True, "note": "approved-now"}


@pytest.mark.asyncio
async def test_suspend_internal_api_transitions_state(state_dir: Path) -> None:
    """Internal ctl_suspend_until API still transitions to suspended state."""
    from anima.shell.ctl import ctl_suspend_until

    _write_state("inst_suspend_event", AgentState.running)

    result = await ctl_suspend_until("inst_suspend_event", resume_after="2026-03-01T12:00:00Z")
    assert isinstance(result, Success)

    suspended_state = read_state("inst_suspend_event")
    assert isinstance(suspended_state, Success)
    assert suspended_state.unwrap().state == AgentState.suspended
