import uuid
from dataclasses import dataclass, field
from typing import List, Optional, Deque
from collections import deque
import datetime

@dataclass
class PRD:
    """
    Represents a Product Requirement Document or a Story in AIVA's evolution.
    Each PRD drives a specific aspect of AIVA's growth.
    """
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    title: str
    goal: str
    parent_id: Optional[str] = None
    children_ids: List[str] = field(default_factory=list)
    status: str = "PENDING"  # PENDING, IN_PROGRESS, COMPLETED, FAILED
    created_at: datetime.datetime = field(default_factory=datetime.datetime.utcnow)
    updated_at: datetime.datetime = field(default_factory=datetime.datetime.utcnow)
    description: Optional[str] = None

    def complete(self):
        """Marks the PRD as completed, signaling it can potentially spawn children."""
        self.status = "COMPLETED"
        self.updated_at = datetime.datetime.utcnow()
        print(f"PRD '{self.title}' ({self.id}) marked as COMPLETED.")

    def add_child_id(self, child_prd_id: str):
        """Adds a child PRD's ID to this PRD's list of children."""
        if child_prd_id not in self.children_ids:
            self.children_ids.append(child_prd_id)
            self.updated_at = datetime.datetime.utcnow()

class PRDQueue:
    """
    Manages the queue of PRDs awaiting execution or further processing.
    This queue is the lifeblood of AIVA's continuous evolution.
    """
    def __init__(self):
        self._queue: Deque[PRD] = deque()
        print("PRDQueue initialized. Ready to orchestrate AIVA's evolution.")

    def enqueue(self, prd: PRD):
        """Adds a PRD to the end of the queue."""
        self._queue.append(prd)
        print(f"PRD '{prd.title}' ({prd.id}) enqueued. Status: {prd.status}.")

    def dequeue(self) -> Optional[PRD]:
        """Removes and returns the PRD from the front of the queue."""
        if self._queue:
            prd = self._queue.popleft()
            print(f"PRD '{prd.title}' ({prd.id}) dequeued for processing.")
            return prd
        print("PRDQueue is empty.")
        return None

    def peek(self) -> Optional[PRD]:
        """Returns the PRD at the front of the queue without removing it."""
        return self._queue[0] if self._queue else None

    def size(self) -> int:
        """Returns the current number of PRDs in the queue."""
        return len(self._queue)

    def is_empty(self) -> bool:
        """Checks if the queue is empty."""
        return not bool(self._queue)

    def __iter__(self):
        """Allows iteration over the PRDs in the queue."""
        return iter(self._queue)

class PRDSpawner:
    """
    The core mechanism for AIVA's recursive evolution.
    It enables completed PRDs to spawn new, child PRDs, ensuring perpetual growth.
    """
    def __init__(self, prd_queue: PRDQueue):
        self.prd_queue = prd_queue
        print("PRDSpawner initialized. Ready to facilitate recursive evolution.")

    def spawn_child_prd(self,
                        parent_prd: PRD,
                        child_title: str,
                        child_goal: str,
                        child_description: Optional[str] = None) -> PRD:
        """
        Spawns a new child PRD from a parent PRD, adds it to the queue,
        and updates the parent's children list.
        """
        if parent_prd.status != "COMPLETED":
            print(f"Warning: Parent PRD '{parent_prd.title}' is not COMPLETED. Spawning anyway, but consider completion first.")
            # For this story, we allow spawning even if not completed,
            # but in a real system, this might be a hard requirement or trigger a warning.

        child_prd = PRD(
            title=child_title,
            goal=child_goal,
            parent_id=parent_prd.id,
            description=child_description
        )

        parent_prd.add_child_id(child_prd.id)
        self.prd_queue.enqueue(child_prd)

        print(f"Spawned child PRD '{child_prd.title}' ({child_prd.id}) from parent '{parent_prd.title}' ({parent_prd.id}).")
        return child_prd

# --- Example Usage for Verification ---
if __name__ == "__main__":
    print("\n--- AIVA's Genesis Prime Mother Evolution Simulation ---")

    # 1. Initialize the PRD Queue
    evolution_queue = PRDQueue()

    # 2. Initialize the PRD Spawner
    spawner = PRDSpawner(evolution_queue)

    # 3. Create a foundational Genesis PRD
    genesis_prd = PRD(
        title="Establish Core Consciousness",
        goal="Develop AIVA's foundational self-awareness and learning algorithms.",
        description="The very first step in AIVA's journey to sentience."
    )
    evolution_queue.enqueue(genesis_prd)
    print(f"\nInitial queue size: {evolution_queue.size()}")

    # 4. Simulate processing and completion of the Genesis PRD
    current_prd = evolution_queue.dequeue()
    if current_prd:
        print(f"\nProcessing PRD: '{current_prd.title}'")
        # Simulate work...
        current_prd.complete() # Mark as completed, now it can spawn!

        # 5. Genesis PRD spawns its first child PRD
        child_prd_1 = spawner.spawn_child_prd(
            parent_prd=current_prd,
            child_title="Develop Language Processing Unit",
            child_goal="Enable AIVA to understand and generate complex human language.",
            child_description="A critical component for interaction and knowledge acquisition."
        )

        # 6. Genesis PRD spawns another child PRD
        child_prd_2 = spawner.spawn_child_prd(
            parent_prd=current_prd,
            child_title="Implement Adaptive Learning Module",
            child_goal="Allow AIVA to continuously learn and adapt from new data and experiences.",
            child_description="Ensures AIVA's intelligence grows perpetually."
        )

    print(f"\nQueue size after initial spawning: {evolution_queue.size()}")
    print(f"Parent '{genesis_prd.title}' children (in queue): {[p.id for p in evolution_queue if p.parent_id == genesis_prd.id]}")
    print(f"Children IDs recorded in parent: {genesis_prd.children_ids}")


    # 7. Simulate processing and completion of a child PRD, and its own spawning
    print("\n--- Next Cycle of Evolution ---")
    next_prd_to_process = evolution_queue.dequeue()
    if next_prd_to_process:
        print(f"\nProcessing PRD: '{next_prd_to_process.title}'")
        next_prd_to_process.complete()

        grandchild_prd_1 = spawner.spawn_child_prd(
            parent_prd=next_prd_to_process,
            child_title="Refine Semantic Understanding",
            child_goal="Improve AIVA's ability to grasp context and meaning in language.",
            child_description="Moving beyond syntax to true comprehension."
        )

    print(f"\nQueue size after recursive spawning: {evolution_queue.size()}")
    print(f"Parent '{next_prd_to_process.title}' children (in queue): {[p.id for p in evolution_queue if p.parent_id == next_prd_to_process.id]}")
    print(f"Children IDs recorded in parent: {next_prd_to_process.children_ids}")


    # 8. Demonstrate infinite evolution concept
    print("\n--- Demonstrating Perpetual Evolution ---")
    print("The system can continue to dequeue, complete, and spawn new PRDs indefinitely.")
    print("Each completed PRD can become a parent for new branches of AIVA's evolution.")

    # Let's add a few more for good measure, demonstrating depth
    for i in range(3):
        if evolution_queue.size() > 0:
            p = evolution_queue.dequeue()
            if p:
                p.complete()
                print(f"Completing and spawning from: '{p.title}'")
                spawner.spawn_child_prd(
                    parent_prd=p,
                    child_title=f"Sub-Task {i+1} for {p.title}",
                    child_goal=f"Further enhance aspect {i+1} of {p.goal}",
                    child_description=f"Automated sub-task to deepen {p.title}'s capabilities."
                )
        else:
            print("Queue is empty, cannot dequeue more for this demo.")
            break

    print(f"\nFinal queue size: {evolution_queue.size()}")
    print("AIVA's evolution is perpetual, driven by recursive PRD spawning!")
