"""Pydantic request/response models for screening API."""

from __future__ import annotations
from typing import Any, Literal, Optional  # noqa: F401 — Literal used at runtime by Pydantic
from pydantic import BaseModel


class ScreeningRequest(BaseModel):
    """Request to screen papers."""

    project_id: Optional[int] = None
    papers: list[dict[str, str]]  # Each with id, title, abstract, citation
    criteria: list[dict[str, str]] = []  # Each with name, type, value
    questions: list[str] = []
    model: str = "gpt-5-nano"
    repetitions: int = 5
    threshold: float = 1.0
    clusters_type: Literal["include", "exclude"] | None = None
    mock: bool = False  # Use MockAIService
    max_estimated_cost_usd: Optional[float] = None  # Cost ceiling; 400 if exceeded


class ScreeningJobResponse(BaseModel):
    job_id: str
    status: str = "pending"
    progress: float = 0.0
    stage: str = ""


class ScreeningResultResponse(BaseModel):
    job_id: str
    status: str
    progress: float
    stage: str
    results: Optional[list[dict[str, Any]]] = None
    clusters: Optional[list[dict[str, Any]]] = None
    error: Optional[str] = None
    error_category: Optional[str] = None
    error_retryable: Optional[bool] = None
    # Provenance
    model_version: Optional[str] = None
    # Diagnostics
    config: Optional[dict[str, Any]] = None
    stage_timings: Optional[dict[str, float]] = None  # {stage_name: duration_ms}
    duration_ms: Optional[int] = None
    estimated_cost_usd: Optional[float] = None
    created_at: Optional[str] = None
    completed_at: Optional[str] = None


class ScreeningJobListItem(BaseModel):
    """Summary item for job listing."""

    job_id: str
    status: str
    progress: float
    stage: str
    papers_count: int = 0
    model: str = ""
    project_id: Optional[int] = None
    project_name: Optional[str] = None
    duration_ms: Optional[int] = None
    estimated_cost_usd: Optional[float] = None
    created_at: Optional[str] = None
    completed_at: Optional[str] = None


class ScreeningCostEstimateRequest(BaseModel):
    """Request to estimate screening cost before running."""

    model: str = "gpt-5-nano"
    papers_count: int
    repetitions: int = 5
    criteria_count: int = 0


class ScreeningCostEstimateResponse(BaseModel):
    estimated_input_tokens: int
    estimated_output_tokens: int
    estimated_cost_usd: float
    model: str
    papers_count: int
    repetitions: int
    confidence: str = "approximate"
    disclaimer: str = (
        "Estimate based on empirical averages. Actual cost may vary +-30% "
        "depending on paper length and criteria complexity."
    )
