"""
Optimal API Schemas

Request/response models for knowledge base and RAG endpoints.
"""

from typing import Any
from uuid import UUID

from pydantic import BaseModel, Field


class IndexCodeRequest(BaseModel):
    """Request to index code files."""

    sources: list[str] = Field(
        ..., min_length=1, description="File paths, directories, or globs"
    )
    project: str | None = Field(None, description="Project identifier for filtering")


class IndexDocsRequest(BaseModel):
    """Request to index documentation."""

    sources: list[str] = Field(
        ..., min_length=1, description="File paths, URLs, or globs"
    )
    project: str | None = Field(None, description="Project identifier for filtering")


class SearchRequest(BaseModel):
    """Request for semantic search."""

    query: str = Field(..., min_length=1, description="Natural language query")
    project: str | None = Field(None, description="Filter by project")
    task_id: UUID | None = Field(None, description="Filter by task")
    index_types: list[str] | None = Field(None, description="Index types to search")
    top_k: int = Field(5, ge=1, le=20, description="Number of results")


class RAGQueryRequest(BaseModel):
    """Request for RAG query."""

    query: str = Field(..., min_length=1, description="Natural language question")
    project: str | None = Field(None, description="Filter by project")
    task_id: UUID | None = Field(None, description="Filter by task")
    index_types: list[str] | None = Field(None, description="Index types to query")
    top_k: int = Field(5, ge=1, le=20, description="Context chunks to use")


class SearchResultResponse(BaseModel):
    """A single search result."""

    content: str
    source: str
    score: float
    index_type: str
    metadata: dict[str, Any] = Field(default_factory=dict)


class SearchResponse(BaseModel):
    """Response from semantic search."""

    results: list[SearchResultResponse]
    query: str
    total: int


class RAGQueryResponse(BaseModel):
    """Response from RAG query."""

    answer: str
    citations: list[SearchResultResponse]
    query: str
    context_used: int
    search_stats: dict[str, int] | None = Field(
        default=None, description="Results count per index (-1 = error)"
    )
    search_errors: dict[str, str] | None = Field(
        default=None, description="Error messages for failed indexes"
    )


class IndexStatsResponse(BaseModel):
    """Statistics for all indexes."""

    initialized: bool
    indexes: dict[str, dict[str, Any]]


class SingleIndexStatsResponse(BaseModel):
    """Statistics for a single index."""

    index_type: str
    document_count: int
    chunk_count: int
    last_updated: str | None = None


class RAGHealthResponse(BaseModel):
    """Response from RAG health check."""

    healthy: bool
    embedding_status: str = Field(..., description="Embedding model status")
    llm_status: str = Field(..., description="LLM (answer synthesis) status")
    vector_store_status: str = Field(..., description="Vector store status")
    details: dict[str, Any] = Field(default_factory=dict)


class RefreshRequest(BaseModel):
    """Request to refresh an index."""

    index_type: str = Field(..., description="Index type to refresh")
    # Empty / omitted list means "refresh every source currently registered
    # for this index" — the refresh route discovers them from
    # `indexed_documents`. This is what the panel's Refresh All button
    # sends, which was rejecting with a 422 under the old min_length=1.
    sources: list[str] = Field(
        default_factory=list,
        description="Sources to refresh (empty = all sources in this index)",
    )


class IndexResponse(BaseModel):
    """Response from indexing operations."""

    indexed: int
    sources: list[str]
    project: str | None


class DocumentListItem(BaseModel):
    """A document in an index."""

    id: str
    source: str
    indexed_at: str
    metadata: dict[str, Any] = Field(default_factory=dict)


class PaginationParams(BaseModel):
    """Pagination query parameters."""

    limit: int = Field(50, ge=1, le=100, description="Max items to return")
    offset: int = Field(0, ge=0, description="Skip items")


class DocumentListResponse(BaseModel):
    """Response from listing documents in an index."""

    documents: list[DocumentListItem]
    total: int
    index_type: str


class ClearIndexResponse(BaseModel):
    """Response from clearing an index."""

    status: str
    index_type: str


class RefreshIndexResponse(BaseModel):
    """Response from refreshing an index."""

    status: str
    index_type: str
    sources: list[str]


class PromptTemplateRequest(BaseModel):
    """Request to create/manage a prompt template."""

    name: str = Field(..., min_length=1, max_length=100, description="Template name")
    template: str = Field(..., min_length=1, description="Prompt template")
    description: str | None = Field(None, description="Template description")
    variables: list[str] = Field(default_factory=list, description="Variables")
    category: str | None = Field(None, description="Template category")


class PromptTemplateResponse(BaseModel):
    """Response for prompt template."""

    id: str
    name: str
    template: str
    description: str | None
    variables: list[str]
    category: str | None
    created_at: str


class TokenEstimateRequest(BaseModel):
    """Request to estimate token count."""

    content: str = Field(..., min_length=1, description="Content to estimate")
    model: str = Field("claude-sonnet-4-20250514", description="Model")


class TokenEstimateResponse(BaseModel):
    """Response with token count estimate."""

    token_count: int
    model: str
    content_length: int


# =============================================================================
# OPTIMAL BRAIN SCHEMAS
# =============================================================================


# Mentor Schemas
class MentorAskRequest(BaseModel):
    """Request to ask the mentor a question."""

    question: str = Field(..., min_length=1, description="Question to ask")
    conversation_id: str | None = Field(None, description="Continue conversation")
    domain: str | None = Field(
        None, description="Domain filter (coding, security, workflow)"
    )


class MentorAskResponse(BaseModel):
    """Response from mentor."""

    answer: str
    sources: list[SearchResultResponse]
    conversation_id: str
    suggested_followups: list[str]
    search_stats: dict[str, int] | None = Field(
        default=None, description="Results count per index (-1 = error)"
    )
    search_errors: dict[str, str] | None = Field(
        default=None, description="Error messages for failed indexes"
    )


# Error Schemas
class ErrorSearchRequest(BaseModel):
    """Request to search for error solutions."""

    error_message: str = Field(..., min_length=1, description="Error message")
    context: str = Field("", description="Additional context")


class ErrorSearchResponse(BaseModel):
    """Response from error search."""

    results: list[SearchResultResponse]
    total: int


class ErrorRecordRequest(BaseModel):
    """Request to record an error solution."""

    error_message: str = Field(..., min_length=1, description="Error message")
    context: str = Field(..., description="Context when error occurred")
    solution: str = Field(..., min_length=1, description="How it was fixed")
    worked: bool = Field(True, description="Whether the solution worked")
    tags: list[str] = Field(default_factory=list, description="Tags")


class ErrorRecordResponse(BaseModel):
    """Response from recording an error."""

    error_id: str
    status: str


# Decision Schemas
class DecisionCheckRequest(BaseModel):
    """Request to check for decision precedents."""

    topic: str = Field(..., min_length=1, description="Decision topic")


class DecisionCheckResponse(BaseModel):
    """Response from decision check."""

    has_precedent: bool
    decisions: list[dict[str, Any]]
    recommendation: str


class DecisionRecordRequest(BaseModel):
    """Request to record a decision."""

    topic: str = Field(..., min_length=1, description="Decision topic")
    decision: str = Field(..., min_length=1, description="The decision made")
    rationale: str = Field(..., min_length=1, description="Why this decision")
    alternatives: list[dict[str, Any]] = Field(
        default_factory=list, description="Alternatives considered"
    )
    context: str = Field("", description="Additional context")
    scope: str = Field("team", description="Scope: team or org")
    tags: list[str] = Field(default_factory=list, description="Tags")


class DecisionRecordResponse(BaseModel):
    """Response from recording a decision."""

    decision_id: str
    status: str


# Standards Schemas
class StandardsGetRequest(BaseModel):
    """Request to get standards."""

    domain: str = Field(..., description="Domain: coding, security, workflow")
    language: str | None = Field(None, description="Language filter")


class StandardsGetResponse(BaseModel):
    """Response with standards."""

    standards: list[SearchResultResponse]
    total: int


class ValidateActionRequest(BaseModel):
    """Request to validate an action against standards."""

    action_type: str = Field(..., description="Type of action")
    context: str = Field(..., description="Action details/code")


class ValidateActionResponse(BaseModel):
    """Response from action validation."""

    allowed: bool
    violations: list[dict[str, Any]]
    warnings: list[dict[str, Any]]
    relevant_standards: list[SearchResultResponse]


# Code Review Schemas
class CodeReviewRequest(BaseModel):
    """Request to review code."""

    code: str = Field(..., min_length=1, description="Code to review")
    file_path: str = Field(..., min_length=1, description="File path being reviewed")
    change_type: str = Field("modify", description="Change type: add, modify, delete")


class CodeReviewResponse(BaseModel):
    """Response from code review."""

    file_path: str
    approved: bool
    score: float = Field(ge=0, le=100, description="Review score 0-100")
    comments: list[dict[str, Any]]
    standards_checked: list[str]
    similar_reviews: list[str]


# Learning Schemas
class LearningRecordRequest(BaseModel):
    """Request to record a learning."""

    content: str = Field(..., min_length=1, description="Learning content")
    category: str = Field(
        ...,
        min_length=1,
        description="Category: error_handling, performance, testing, pattern, etc.",
    )
    team: str | None = Field(None, description="Team: backend, frontend, ux_ui")
    shareable: bool = Field(True, description="Share with other agents?")
    tags: list[str] = Field(default_factory=list, description="Tags")


class LearningRecordResponse(BaseModel):
    """Response from recording a learning."""

    learning_id: str
    status: str


class LearningSearchRequest(BaseModel):
    """Request to search learnings."""

    query: str = Field(..., min_length=1, description="Search query")
    category: str | None = Field(None, description="Category filter")
    team: str | None = Field(None, description="Team filter")
    top_k: int = Field(10, ge=1, le=50, description="Number of results")


# =============================================================================
# Proactive Context Schemas
# =============================================================================


class ProactiveContextRequest(BaseModel):
    """Request to fetch proactive context for a task."""

    task_id: UUID = Field(..., description="Task ID to get context for")


class ProactiveContextItem(BaseModel):
    """A single proactive context item."""

    content: str = Field(..., description="Context content")
    source: str = Field(..., description="Source of this context")
    score: float = Field(..., description="Relevance score")
    index_type: str = Field(..., description="Type of index this came from")
    metadata: dict[str, Any] = Field(
        default_factory=dict, description="Additional metadata"
    )


class ProactiveContextResponse(BaseModel):
    """Response with proactive context for a task."""

    task_id: UUID | None = Field(
        None, description="Task ID (if context is task-specific)"
    )
    agent_id: UUID | None = Field(None, description="Agent ID")
    similar_tasks: list[ProactiveContextItem] = Field(
        default_factory=list, description="Similar past tasks"
    )
    relevant_learnings: list[ProactiveContextItem] = Field(
        default_factory=list, description="Relevant learnings from past work"
    )
    code_patterns: list[ProactiveContextItem] = Field(
        default_factory=list, description="Relevant code patterns"
    )
    applicable_standards: list[ProactiveContextItem] = Field(
        default_factory=list, description="Applicable standards and rules"
    )
    recent_decisions: list[ProactiveContextItem] = Field(
        default_factory=list, description="Recent relevant decisions"
    )
    known_issues: list[ProactiveContextItem] = Field(
        default_factory=list, description="Known issues that may apply"
    )
    summary: str = Field("", description="Summary of the context package")
