import pytest
from unittest.mock import MagicMock, patch
from src import multi_agent_conductor
from src.models import Ticket, WorkerContext
from src import events
import threading
from typing import Generator

class MockDialog:
 def __init__(self, approved: bool, final_payload: dict | None = None) -> None:
  self.approved = approved
  self.final_payload = final_payload

 def wait(self) -> dict:
  res = {'approved': self.approved, 'abort': False}
  if self.final_payload:
   res.update(self.final_payload)
  return res

@pytest.fixture
def mock_ai_client() -> Generator[MagicMock, None, None]:
 with patch("src.ai_client.send") as mock_send:
  mock_send.return_value = "Task completed"
  yield mock_send

def test_confirm_spawn_pushed_to_queue() -> None:
 event_queue = events.SyncEventQueue()
 ticket_id = "T1"
 role = "Tier 3 Worker"
 prompt = "Original Prompt"
 context_md = "Original Context"

 results = []
 def run_confirm():
  res = multi_agent_conductor.confirm_spawn(role, prompt, context_md, event_queue, ticket_id)
  results.append(res)
 
 t = threading.Thread(target=run_confirm)
 t.start()
 
 # Wait for the event to appear in the queue
 event_name, payload = event_queue.get()
 assert event_name == "mma_spawn_approval"
 assert payload["ticket_id"] == ticket_id
 assert payload["role"] == role
 assert payload["prompt"] == prompt
 assert payload["context_md"] == context_md
 assert "dialog_container" in payload
 
 # Simulate GUI injecting a dialog
 payload["dialog_container"][0] = MockDialog(True, {"prompt": "Modified Prompt", "context_md": "Modified Context"})
 
 t.join(timeout=5)
 assert not t.is_alive()
 approved, final_prompt, final_context = results[0]
 assert approved is True
 assert final_prompt == "Modified Prompt"
 assert final_context == "Modified Context"

@patch("src.multi_agent_conductor.confirm_spawn")
def test_run_worker_lifecycle_approved(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
 ticket = Ticket(id="T1", description="desc", status="todo", assigned_to="user")
 context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
 event_queue = app_instance.controller.event_queue
 mock_confirm.return_value = (True, "Modified Prompt", "Modified Context")
 multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
 mock_confirm.assert_called_once()
 # Check that ai_client.send was called with modified values
 args, kwargs = mock_ai_client.call_args
 assert kwargs["user_message"] == "Modified Prompt"
 assert kwargs["md_content"] == "Modified Context"
 assert ticket.status == "completed"

@patch("src.multi_agent_conductor.confirm_spawn")
def test_run_worker_lifecycle_rejected(mock_confirm: MagicMock, mock_ai_client: MagicMock, app_instance) -> None:
 ticket = Ticket(id="T1", description="desc", status="todo", assigned_to="user")
 context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
 event_queue = app_instance.controller.event_queue
 mock_confirm.return_value = (False, "Original Prompt", "Original Context")
 result = multi_agent_conductor.run_worker_lifecycle(ticket, context, event_queue=event_queue)
 mock_confirm.assert_called_once()
 mock_ai_client.assert_not_called()
 assert ticket.status == "blocked"
 assert "Spawn rejected by user" in ticket.blocked_reason
 assert "BLOCKED" in result
