from typing import Any, List, Dict, Protocol, Optional
from pydantic import BaseModel, Field, field_validator

class ProjectRequest(BaseModel):
    """Data model for a project generation request."""
    project_name: str = Field(
        ...,
        description="The name of the project to be generated.",
        examples=["MCP Library"]
    )
    dynamic_tools: List[Dict[str, Any]] = Field(
        default=[],
        description="A list of JSON objects that define the tools to be created.",
        examples=[{
            "name": "search_books_by_author",
            "description": "Search for books by author",
            "params": "author_name: str, genre: str = None",
            "return_type": "List[Dict[str, Any]]"
        }]
    )
    dynamic_prompts: List[Dict[str, Any]] = Field(
        default=[],
        description="A list of JSON objects that define dynamic prompts.",
        examples=[{
            "name": "customer_support_prompt",
            "description": "System prompt for customer support context."
        }]
    )
    dynamic_resources: List[Dict[str, Any]] = Field(
        default=[],
        description="A list of JSON objects that define dynamic resources.",
        examples=[{
            "name": "return_policy",
            "uri": "policy://company/{policy_name}",
            "description": "Retrieves a company policy document.",
            "params": "policy_name: str",
            "return_type": "Dict[str, Any]"
        }]
    )


class GeneratedProjectInfo(BaseModel):
    temp_dir: str
    output_path: Optional[str] = None
    zip_path: Optional[str] = None
    zip_filename: Optional[str] = None


class ProjectGeneratorGateway(Protocol):
    """
    Defines the contract (interface) for any adapter that generates projects.
    """
    def generate(self, project_data: ProjectRequest) -> GeneratedProjectInfo:
        """
        Generates the project structure, compresses it, and returns the file path.
        """
        ...

class ProjectInventory(BaseModel):
    """Data model for the inventory of an existing project."""
    is_valid: bool
    project_path: str
    existing_tools: List[str] = Field(default_factory=list)
    existing_prompts: List[str] = Field(default_factory=list)
    existing_resources: List[str] = Field(default_factory=list)
    existing_resource_uris: List[str] = Field(default_factory=list)

class ProjectAnalyzerGateway(Protocol):
    """Defines the contract for an adapter that analyzes a project's structure."""
    def analyze(self, path: str) -> ProjectInventory:
        ...

class CodeInjectorGateway(Protocol):
    """Defines the contract for an adapter that injects code into a project."""
    def inject_tools(self, tools: List[Dict[str, Any]], inventory: ProjectInventory):
        ...
    def inject_prompts(self, prompts: List[Dict[str, Any]], inventory: ProjectInventory):
        ...
    def inject_resources(self, resources: List[Dict[str, Any]], inventory: ProjectInventory):
        ...