# Auto-generated by DjangoCFG - see CLAUDE.md

from __future__ import annotations
import datetime
from typing import Any

from pydantic import BaseModel, ConfigDict, Field

from ..enums import SearchAsyncRequestRequestMode


class SearchRequestList(BaseModel):
    """
    Serializer for listing search requests.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    uuid: str = ...
    mode: str = ...
    status: str = ...
    query: str = ...
    model: str = ...
    tokens_input: int = ...
    tokens_output: int = ...
    cost_usd: float = ...
    duration_ms: int | None = None
    cached: bool = ...
    created_at: datetime.datetime = ...



class SearchRequestListRequest(BaseModel):
    """
    Serializer for listing search requests.

    Request model (no read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    uuid: str = ...
    mode: str = Field(min_length=1)
    status: str = Field(min_length=1)
    query: str = Field(min_length=1)
    model: str = Field(min_length=1)
    tokens_input: int = ...
    tokens_output: int = ...
    cost_usd: float = ...
    duration_ms: int | None = None
    cached: bool = ...
    created_at: datetime.datetime = ...



class RankedResult(BaseModel):
    """
    Serializer for a single ranked search result matching agent model.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    url: str = ...
    title: str = ...
    snippet: str | None = None
    domain: str | None = None
    published_date: str | None = None
    relevance: str | None = Field(None, description='Relevance level: high, medium, l...')
    relevance_score: float | None = None
    credibility: str | None = Field(None, description='Source credibility: authoritativ...')
    key_info: str | None = None
    reasoning: str | None = None



class MetricsSummary(BaseModel):
    """
    Flat metrics summary matching agent model. Provides timing, token usage,
    counts, and cost info.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    search_duration_ms: int | None = Field(None, description='Search execution time')
    ranking_duration_ms: int | None = Field(None, description='Ranking execution time')
    total_duration_ms: int | None = Field(None, description='Total execution time')
    llm_calls: int | None = Field(None, description='Number of LLM calls')
    llm_tokens_total: int | None = Field(None, description='Total LLM tokens used')
    tokens_input: int | None = Field(None, description='Input tokens used')
    tokens_output: int | None = Field(None, description='Output tokens generated')
    total_citations: int | None = Field(None, description='Total citations received')
    high_relevance_count: int | None = Field(None, description='High relevance results')
    medium_relevance_count: int | None = Field(None, description='Medium relevance results')
    low_relevance_count: int | None = Field(None, description='Low relevance results')
    cost_usd: float | None = Field(None, description='Total cost in USD')



class QueryDecomposition(BaseModel):
    """
    Query decomposition plan from search analysis. Breaks complex queries into
    optimized sub-queries.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    original_query: str = Field(description='Original user query')
    intent: str | None = Field(None, description='Interpreted user intent')
    sub_queries: list[str] = Field(description='Decomposed sub-queries (list of ...')
    keywords: list[str] | None = Field(None, description='Key terms to look for')
    entities: list[str] | None = Field(None, description='Named entities mentioned')



class RankedResults(BaseModel):
    """
    Response serializer for ranked search results.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    uuid: str = ...
    ranked_results: list[RankedResult] = ...
    summary: str = ...
    key_findings: list[str] = ...
    decomposition: QueryDecomposition | None = None
    metrics: MetricsSummary | None = None



class CrossAnalysis(BaseModel):
    """
    Cross-source analysis results for investigate mode.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    themes: list[str] | None = Field(None, description='Common themes across sources')
    agreements: list[str] | None = Field(None, description='Points of agreement between sources')
    gaps: list[str] | None = Field(None, description='Information gaps identified')



class Contradiction(BaseModel):
    """
    A detected contradiction between sources.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    claim_a: str = Field(description='First conflicting claim')
    source_a: str = Field(description='Source of first claim')
    claim_b: str = Field(description='Second conflicting claim')
    source_b: str = Field(description='Source of second claim')
    severity: str | None = Field(None, description='Severity: minor, moderate, major')



class DetailedAnalysisItem(BaseModel):
    """
    Detailed analysis of a single source.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    url: str = ...
    content_length: int | None = None
    key_points: list[str] | None = None
    credibility: str | None = None



class EntityData(BaseModel):
    """
    Serializer for a single extracted entity.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    value: str = ...
    entity_context: str | None = None
    source_url: str | None = None



class Entities(BaseModel):
    """
    Serializer for all extracted entities by category.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    companies: list[EntityData] | None = None
    people: list[EntityData] | None = None
    amounts: list[EntityData] | None = None
    dates: list[EntityData] | None = None
    locations: list[EntityData] | None = None



class Citation(BaseModel):
    """
    Serializer for search citations.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    url: str = ...
    title: str | None = None
    cited_text: str | None = None
    encrypted_index: str | None = None



class ConfidenceScores(BaseModel):
    """
    Confidence scores for findings.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    overall: float = Field(description='Overall confidence 0-1')
    by_finding: dict[str, Any] | None = Field(None, description='Per-finding confidence scores')



class SubQuery(BaseModel):
    """
    Sub-query used in investigate mode.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    query: str = Field(description='Sub-query text')
    purpose: str | None = Field(None, description='Why this sub-query was generated')
    result_count: int | None = Field(None, description='Number of results found')



class SearchModeResponse(BaseModel):
    """
    Comprehensive response serializer for mode-based search. Fields are
    populated based on the search mode: - search: content, citations - research:
    + ranked_results, summary, key_findings - analyze: + entities -
    comprehensive: + synthesis, detailed_analysis - investigate: + sub_queries,
    cross_analysis, contradictions, confidence_scores

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    uuid: str = ...
    mode: SearchAsyncRequestRequestMode = Field(description='* `search` - Search * `research`...')
    status: str = ...
    query: str = ...
    content: str = ...
    citations: list[Citation] = ...
    ranked_results: list[RankedResult] | None = None
    summary: str | None = None
    key_findings: list[str] | None = None
    decomposition: QueryDecomposition | None = None
    agent_metrics: MetricsSummary | None = None
    entities: Entities | None = None
    synthesis: str | None = None
    detailed_analysis: list[DetailedAnalysisItem] | None = None
    sub_queries: list[SubQuery] | None = None
    cross_analysis: CrossAnalysis | None = None
    contradictions: list[Contradiction] | None = None
    confidence_scores: ConfidenceScores | None = None
    tokens_input: int = ...
    tokens_output: int = ...
    cost_usd: float = ...
    duration_ms: int | None = None
    model: str = ...
    cached: bool = ...
    error: str | None = None



class SearchJobStatus(BaseModel):
    """
    Job status serializer.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    uuid: str = ...
    status: str = ...
    job_id: str | None = None
    queued_at: datetime.datetime | None = None
    started_at: datetime.datetime | None = None
    completed_at: datetime.datetime | None = None
    duration_ms: int | None = None
    error: str | None = None



class URLFetchRequest(BaseModel):
    """
    Serializer for URL fetch requests.

    Request model (no read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    url: str = Field(description='URL to fetch and analyze', min_length=1)
    prompt: str | None = Field(
    None,
    description='Prompt for analyzing the content',
    min_length=1,
    max_length=10000,
)
    max_tokens: int | None = Field(None, description='Maximum tokens for response', ge=1, le=4096)



class SearchResponse(BaseModel):
    """
    Serializer for search responses.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    content: str = ...
    citations: list[Citation] = ...
    tokens_input: int = ...
    tokens_output: int = ...
    cost_usd: float = ...
    duration_ms: int = ...
    model: str = ...
    cached: bool = ...
    error: str | None = None
    request_id: str | None = None



class UserLocationRequest(BaseModel):
    """
    Serializer for user location.

    Request model (no read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    country: str | None = Field(None, description='ISO 3166-1 alpha-2 country code', max_length=2)
    region: str | None = Field(None, description='Region/state name', max_length=100)
    city: str | None = Field(None, description='City name', max_length=100)



class SearchQueryRequest(BaseModel):
    """
    Serializer for web search requests.

    Request model (no read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    query: str = Field(description='Search query', min_length=1, max_length=10000)
    max_tokens: int | None = Field(None, description='Maximum tokens for response', ge=1, le=4096)
    max_searches: int | None = Field(
    None,
    description='Maximum number of web searches',
    ge=1,
    le=20,
)
    allowed_domains: list[str] | None = Field(None, description='Only search these domains')
    blocked_domains: list[str] | None = Field(
    None,
    description='Exclude these domains from search',
)
    user_location: UserLocationRequest | None = None



class SearchAsyncRequestRequest(BaseModel):
    """
    Request serializer for async search with agent. Modes (progressive
    capabilities): - search: Direct web search (fastest) - research: + LLM
    ranking + summary - analyze: + entity extraction - comprehensive: + URL
    fetch + deep synthesis - investigate: + multi-query + cross-analysis

    Request model (no read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    query: str = Field(description='Search query', min_length=1, max_length=10000)
    mode: SearchAsyncRequestRequestMode | None = Field(
    None,
    description='Search mode determining analysis...',
)
    task_prompt: str | None = Field(
    None,
    description='Custom instructions for LLM anal...',
    max_length=2000,
)
    model: str | None = Field(
    None,
    description='LLM model for ranking/analysis (...',
    min_length=1,
)
    max_results: int | None = Field(None, description='Maximum results to return', ge=1, le=50)
    allowed_domains: list[str] | None = Field(None, description='Only search these domains')
    blocked_domains: list[str] | None = Field(None, description='Exclude these domains')



class SearchAsyncResponse(BaseModel):
    """
    Response serializer for async job submission.

    Response model (includes read-only fields).
    """

    model_config = ConfigDict(
        validate_assignment=True,
        extra="allow",
        frozen=False,
    )

    status: str = ...
    job_id: str | None = None
    request_uuid: str = ...
    message: str = ...
    status_url: str = ...



