from src.models import Ticket, Track, WorkerContext
from src.dag_engine import get_executable_tickets

def test_ticket_instantiation() -> None:
 """
 
  
      Verifies that a Ticket can be instantiated with its required fields:
      id, description, status, assigned_to.
 """
 ticket_id = "T1"
 description = "Implement surgical code changes"
 status = "todo"
 assigned_to = "tier3-worker"
 ticket = Ticket(
  id=ticket_id,
  description=description,
  status=status,
  assigned_to=assigned_to
 )
 assert ticket.id == ticket_id
 assert ticket.description == description
 assert ticket.status == status
 assert ticket.assigned_to == assigned_to
 assert ticket.depends_on == []

def test_ticket_with_dependencies() -> None:
 """
 
  
      Verifies that a Ticket can store dependencies.
 """
 ticket = Ticket(
  id="T2",
  description="Write code",
  status="todo",
  assigned_to="worker-1",
  depends_on=["T1"]
 )
 assert ticket.depends_on == ["T1"]

def test_track_instantiation() -> None:
 """
 
  
      Verifies that a Track can be instantiated with its required fields:
      id, description, and a list of Tickets.
 """
 ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
 ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="b")
 track_id = "TRACK-1"
 track_desc = "Implement MMA Models"
 tickets = [ticket1, ticket2]
 track = Track(
  id=track_id,
  description=track_desc,
  tickets=tickets
 )
 assert track.id == track_id
 assert track.description == track_desc
 assert len(track.tickets) == 2
 assert track.tickets[0].id == "T1"
 assert track.tickets[1].id == "T2"

def test_track_can_handle_empty_tickets() -> None:
 """
 
  
      Verifies that a Track can be instantiated with an empty list of tickets.
 """
 track = Track(id="TRACK-2", description="Empty Track", tickets=[])
 assert track.tickets == []

def test_worker_context_instantiation() -> None:
 """
 
  
      Verifies that a WorkerContext can be instantiated with ticket_id, 
      model_name, and messages.
 """
 ticket_id = "T1"
 model_name = "gemini-2.0-flash-lite"
 messages = [
  {"role": "user", "content": "Hello"},
  {"role": "assistant", "content": "Hi there!"}
 ]
 context = WorkerContext(
  ticket_id=ticket_id,
  model_name=model_name,
  messages=messages
 )
 assert context.ticket_id == ticket_id
 assert context.model_name == model_name
 assert context.messages == messages

def test_ticket_mark_blocked() -> None:
 """
 
  
      Verifies that ticket.mark_blocked(reason) sets the status to 'blocked'.
      Note: The reason field might need to be added to the Ticket class.
 """
 ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
 ticket.mark_blocked("Waiting for API key")
 assert ticket.status == "blocked"

def test_ticket_mark_complete() -> None:
 """
 
  
      Verifies that ticket.mark_complete() sets the status to 'completed'.
 """
 ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
 ticket.mark_complete()
 assert ticket.status == "completed"

def test_track_get_executable_tickets() -> None:
 """
 
  
      Verifies that get_executable_tickets(track) returns only 'todo' tickets
      whose dependencies are all 'completed'.
 """
 # T1: todo, no deps -> executable
 t1 = Ticket(id="T1", description="T1", status="todo", assigned_to="a")
 # T2: todo, deps [T1] -> not executable (T1 is todo)
 t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="a", depends_on=["T1"])
 # T3: todo, deps [T4] -> not executable (T4 is blocked)
 t3 = Ticket(id="T3", description="T3", status="todo", assigned_to="a", depends_on=["T4"])
 # T4: blocked, no deps -> not executable (not 'todo')
 t4 = Ticket(id="T4", description="T4", status="blocked", assigned_to="a")
 # T5: completed, no deps -> not executable (not 'todo')
 t5 = Ticket(id="T5", description="T5", status="completed", assigned_to="a")
 # T6: todo, deps [T5] -> executable (T5 is completed)
 t6 = Ticket(id="T6", description="T6", status="todo", assigned_to="a", depends_on=["T5"])
 track = Track(id="TR1", description="Track 1", tickets=[t1, t2, t3, t4, t5, t6])
 executable = get_executable_tickets(track)
 executable_ids = [t.id for t in executable]
 assert "T1" in executable_ids
 assert "T6" in executable_ids
 assert len(executable_ids) == 2

def test_track_get_executable_tickets_complex() -> None:
 """
 
  
      Verifies executable tickets with complex dependency chains.
      Chain: T1 (comp) -> T2 (todo) -> T3 (todo)
             T4 (comp) -> T3
             T5 (todo) -> T3
 """
 t1 = Ticket(id="T1", description="T1", status="completed", assigned_to="a")
 t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="a", depends_on=["T1"])
 t3 = Ticket(id="T3", description="T3", status="todo", assigned_to="a", depends_on=["T2", "T4", "T5"])
 t4 = Ticket(id="T4", description="T4", status="completed", assigned_to="a")
 t5 = Ticket(id="T5", description="T5", status="todo", assigned_to="a")
 track = Track(id="TR1", description="Track 1", tickets=[t1, t2, t3, t4, t5])
 # At this point:
 # T1 is completed
 # T4 is completed
 # T2 is todo, depends on T1 (completed) -> Executable
 # T5 is todo, no deps -> Executable
 # T3 is todo, depends on T2 (todo), T4 (completed), T5 (todo) -> Not executable
 executable = get_executable_tickets(track)
 executable_ids = sorted([t.id for t in executable])
 assert executable_ids == ["T2", "T5"]
 # Mark T2 complete
 t2.mark_complete()
 # T3 still depends on T5
 executable = get_executable_tickets(track)
 executable_ids = sorted([t.id for t in executable])
 assert executable_ids == ["T5"]
 # Mark T5 complete
 t5.mark_complete()
 # Now T3 should be executable
 executable = get_executable_tickets(track)
 executable_ids = sorted([t.id for t in executable])
 assert executable_ids == ["T3"]