"""Pydantic request/response schemas for the Langfuse Lens API."""
from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field, field_validator


class InvokeRequest(BaseModel):
    message: str = Field(min_length=1, max_length=20000)
    thread_id: str | None = None
    user_id: str | None = None
    project_id: int | None = None
    model: str | None = None


class LensQueryResponse(BaseModel):
    output: str
    metrics: dict[str, Any] = Field(default_factory=dict)
    thread_id: str | None = None


class LLMSettingsRequest(BaseModel):
    target: str = Field(default="project")
    openai_api_key: str = Field(default="")
    anthropic_api_key: str = Field(default="")
    google_api_key: str = Field(default="")
    gemini_api_key: str = Field(default="")
    openrouter_api_key: str = Field(default="")
    openrouter_base_url: str = Field(default="")
    ollama_base_url: str = Field(default="")
    vllm_base_url: str = Field(default="")
    lmstudio_base_url: str = Field(default="")


class LangfuseSettingsRequest(BaseModel):
    target: str = Field(default="project")
    base_url: str = Field(default="")
    public_key: str = Field(default="")
    secret_key: str = Field(default="")
    environment: str = Field(default="")


class DefaultsSettingsRequest(BaseModel):
    target: str = Field(default="project")
    default_mode: str = Field(default="overview")
    default_limit: int = Field(default=20, ge=1, le=100)
    timezone: str = Field(default="UTC")
    retention_days: int = Field(default=30, ge=1, le=3650)
    default_compare_models: bool = Field(default=False)
    report_summary_model: str = Field(
        default="",
        max_length=128,
        pattern=r"^$|^[a-zA-Z0-9_]+:[a-zA-Z0-9_./-]+$",
        description="Report summary LLM (provider:model)",
    )
    allow_signup: bool | None = Field(default=None, description="Toggle public signup on/off")


class IntegrationsSettingsRequest(BaseModel):
    target: str = Field(default="project")
    slack_webhook: str = Field(default="")
    webhook_url: str = Field(default="")
    email_recipients: list[str] = Field(default_factory=list)
    enabled: bool = Field(default=False)


class ValidateSettingsRequest(BaseModel):
    targets: list[str] = Field(default_factory=lambda: ["langfuse"])


class AuthRegisterRequest(BaseModel):
    username: str = Field(min_length=3, max_length=100)
    password: str = Field(min_length=8, max_length=256)
    role: Literal["viewer", "analyst", "editor", "owner", "ops", "super_admin"] = "analyst"
    langfuse_user_id: str = Field(default="", max_length=200, description="Langfuse user ID for trace matching")


class AuthLoginRequest(BaseModel):
    username: str = Field(min_length=3, max_length=100)
    password: str = Field(min_length=8, max_length=256)
    expires_hours: int | None = Field(default=None, ge=1, le=24 * 30)


class UserLangfuseSettingsRequest(BaseModel):
    base_url: str = Field(default="")
    public_key: str = Field(default="")
    secret_key: str = Field(default="")
    environment: str = Field(default="")


class LangfuseProjectCreateRequest(BaseModel):
    name: str = Field(min_length=1)
    base_url: str = Field(default="")
    public_key: str = Field(default="")
    secret_key: str = Field(default="")
    environment: str = Field(default="")
    is_default: bool = False


class LangfuseProjectUpdateRequest(BaseModel):
    name: str | None = None
    base_url: str | None = None
    public_key: str | None = None
    secret_key: str | None = None
    environment: str | None = None
    is_default: bool | None = None


class AdminUserCreateRequest(BaseModel):
    email: str = Field(min_length=3)
    name: str = Field(min_length=1)
    roles: list[str] = Field(default_factory=lambda: ["viewer"])


class AdminUserUpdateRequest(BaseModel):
    status: Literal["active", "suspended"] | None = None
    name: str | None = None


class AdminUserRolesRequest(BaseModel):
    roles: list[str] = Field(default_factory=list)


class ReloadConfigRequest(BaseModel):
    scope: Literal["runtime", "prompts", "integrations", "all"] = "all"


class AdminTokenCreateRequest(BaseModel):
    name: str = Field(min_length=1)
    role: Literal["viewer", "analyst", "editor", "owner", "ops", "super_admin"] = "owner"
    scopes: list[str] = Field(default_factory=list)
    subject: str = Field(default="")
    expires_days: int | None = Field(default=None, ge=1, le=3650)
    auto_rotate: bool = True
    rotate_before_days: int | None = Field(default=None, ge=1, le=3650)


class LangfuseControlRequest(BaseModel):
    operation: str = Field(default="status")
    params: dict[str, Any] = Field(default_factory=dict)


class LangfuseControlMessageRequest(BaseModel):
    message: str = Field(min_length=1)


class OpenApiExecuteRequest(BaseModel):
    operation_id: str | None = None
    method: str | None = None
    path: str | None = None
    path_params: dict[str, Any] = Field(default_factory=dict)
    query: dict[str, Any] = Field(default_factory=dict)
    body: dict[str, Any] | None = None
    refresh_spec: bool = False


class PromptUpsertRequest(BaseModel):
    name: str = Field(min_length=1)
    prompt: Any
    type: str = Field(default="text")
    labels: list[str] = Field(default_factory=list)
    tags: list[str] = Field(default_factory=list)
    commit_message: str = Field(default="")
    config: dict[str, Any] = Field(default_factory=dict)


class PromptPatchRequest(BaseModel):
    prompt: Any | None = None
    type: str = Field(default="text")
    labels: list[str] | None = None
    tags: list[str] | None = None
    commit_message: str = Field(default="")
    config: dict[str, Any] | None = None


class PromptPromoteLabelRequest(BaseModel):
    label: str = Field(min_length=1)
    version: int | None = None


class DatasetCreateRequest(BaseModel):
    name: str = Field(min_length=1)
    description: str = Field(default="")
    metadata: dict[str, Any] = Field(default_factory=dict)


class DatasetItemsUpsertRequest(BaseModel):
    items: list[dict[str, Any]] = Field(default_factory=list)


class DatasetImportFromTracesRequest(BaseModel):
    trace_ids: list[str] = Field(default_factory=list)
    item_template: dict[str, Any] = Field(default_factory=dict)


class ScoreCreateRequest(BaseModel):
    name: str = Field(min_length=1)
    value: float
    trace_id: str = Field(default="")
    observation_id: str = Field(default="")
    comment: str = Field(default="")
    metadata: dict[str, Any] = Field(default_factory=dict)


class AnnotationCreateRequest(BaseModel):
    label: str = Field(min_length=1)
    trace_id: str = Field(default="")
    observation_id: str = Field(default="")
    comment: str = Field(default="")
    metadata: dict[str, Any] = Field(default_factory=dict)


class ReportGenerateRequest(BaseModel):
    target_user_id: str = Field(min_length=1)
    period_type: Literal["daily", "weekly", "monthly"] = Field(default="daily")
    period_start: str = Field(min_length=10, max_length=10, pattern=r"^\d{4}-\d{2}-\d{2}$")
    project_id: int | None = None

    @field_validator("period_start")
    @classmethod
    def _parse_period_start(cls, v: str) -> str:
        from datetime import datetime as _dt

        try:
            _dt.strptime(v, "%Y-%m-%d")
        except ValueError:
            raise ValueError(f"invalid date: {v!r} (expected YYYY-MM-DD)")
        return v


class ExperimentCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=200)
    description: str = Field(default="", max_length=1000)
    experiment_type: Literal["replay", "ab_test", "eval", "comparison"] = Field(...)
    config: dict[str, Any] = Field(default_factory=dict)
    project_id: str | None = None
