"""Pydantic request/response schemas for the API surface."""

from __future__ import annotations

import uuid
from datetime import datetime

from pydantic import BaseModel, ConfigDict, EmailStr, Field

from legate.agent.enums import RunStatus
from legate.policy.roles import Role

# --- Auth -----------------------------------------------------------------


class RegisterRequest(BaseModel):
    email: EmailStr
    password: str = Field(min_length=8, max_length=256)
    name: str = Field(default="", max_length=255)


class LoginRequest(BaseModel):
    email: EmailStr
    password: str


class RefreshRequest(BaseModel):
    refresh_token: str


class TokenResponse(BaseModel):
    access_token: str
    refresh_token: str
    token_type: str = "bearer"
    workspace_id: uuid.UUID | None = None


class UserOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    email: EmailStr
    name: str
    is_active: bool
    is_superuser: bool
    created_at: datetime


# --- Workspaces -----------------------------------------------------------


class WorkspaceCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    slug: str | None = Field(default=None, max_length=255)


class WorkspaceOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    name: str
    slug: str
    plan: str
    created_at: datetime
    role: Role | None = None


class WorkspaceCreateResponse(BaseModel):
    workspace: WorkspaceOut
    access_token: str
    token_type: str = "bearer"


class SwitchResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    workspace_id: uuid.UUID


# --- Members --------------------------------------------------------------


class MemberInvite(BaseModel):
    email: EmailStr
    role: Role = Role.VIEWER


class RoleUpdate(BaseModel):
    role: Role


class MemberOut(BaseModel):
    id: uuid.UUID  # membership id
    user_id: uuid.UUID
    email: EmailStr
    name: str
    role: Role
    created_at: datetime


# --- API keys -------------------------------------------------------------


class ApiKeyCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    # Provide explicit scopes, or a role to derive an equivalent scope set.
    scopes: list[str] | None = None
    role: Role | None = None


class ApiKeyOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    name: str
    prefix: str
    scopes: list[str]
    last_used_at: datetime | None
    revoked_at: datetime | None
    created_at: datetime


class ApiKeyCreateResponse(BaseModel):
    api_key: ApiKeyOut
    # The full secret — shown exactly once and never retrievable again.
    plaintext: str


# --- Audit ----------------------------------------------------------------


class AuditOut(BaseModel):
    id: uuid.UUID
    seq: int
    actor: str
    action: str
    target: str | None
    metadata: dict
    hash: str
    hash_prev: str | None
    created_at: datetime


# --- Tools ----------------------------------------------------------------


class ToolOut(BaseModel):
    name: str
    description: str
    parameters: dict
    is_sensitive: bool
    scopes: list[str]


# --- Agents ---------------------------------------------------------------


class AgentCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    description: str = Field(default="", max_length=1024)
    system_prompt: str = Field(default="")
    provider: str = Field(default="", max_length=50)
    model: str = Field(default="", max_length=255)
    tools: list[str] = Field(default_factory=list)
    memory_config: dict = Field(default_factory=dict)
    guardrails_json: dict = Field(default_factory=dict)


class AgentUpdate(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=255)
    description: str | None = Field(default=None, max_length=1024)
    system_prompt: str | None = None
    provider: str | None = Field(default=None, max_length=50)
    model: str | None = Field(default=None, max_length=255)
    tools: list[str] | None = None
    memory_config: dict | None = None
    guardrails_json: dict | None = None
    is_active: bool | None = None


class AgentOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    name: str
    description: str
    system_prompt: str
    provider: str
    model: str
    tools: list[str]
    memory_config: dict
    guardrails_json: dict
    is_active: bool
    created_at: datetime


# --- Runs and steps -------------------------------------------------------


class RunCreate(BaseModel):
    input: str = Field(default="")


class StepOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    idx: int
    type: str
    name: str
    status: str
    input: dict
    output: dict
    error: str | None
    tokens: int
    created_at: datetime


class RunOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    agent_id: uuid.UUID | None
    workflow_id: uuid.UUID | None = None
    status: RunStatus
    input: dict
    output: dict | None
    error: str | None
    total_tokens: int
    total_steps: int
    started_at: datetime | None
    ended_at: datetime | None
    created_at: datetime


class RunCreateResponse(BaseModel):
    run: RunOut
    stream_url: str


# --- Knowledge base / RAG -------------------------------------------------


class KnowledgeBaseCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    description: str = Field(default="", max_length=1024)
    embedding_provider: str | None = Field(default=None, max_length=50)
    embedding_model: str | None = Field(default=None, max_length=255)


class KnowledgeBaseOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    name: str
    description: str
    embedding_provider: str
    embedding_model: str
    vector_collection: str
    created_at: datetime


class DocumentOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    knowledge_base_id: uuid.UUID
    source: str
    content_type: str
    status: str
    error: str | None
    chunk_count: int
    size_bytes: int
    created_at: datetime


class Citation(BaseModel):
    document_id: str
    knowledge_base_id: str
    source: str
    text: str
    score: float
    chunk_idx: int


class SearchRequest(BaseModel):
    query: str = Field(min_length=1)
    top_k: int = Field(default=5, ge=1, le=50)


class SearchResponse(BaseModel):
    query: str
    results: list[Citation]


# --- Connectors -----------------------------------------------------------


class ConnectorTypeOut(BaseModel):
    type: str
    title: str
    config_schema: dict
    secret_schema: dict
    tools: list[str]


class ConnectorCreate(BaseModel):
    type: str = Field(min_length=1, max_length=50)
    name: str = Field(min_length=1, max_length=255)
    config: dict = Field(default_factory=dict)
    # Plaintext secrets, accepted on write only and never returned.
    secrets: dict = Field(default_factory=dict)


class ConnectorUpdate(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=255)
    config: dict | None = None
    secrets: dict | None = None


class ConnectorOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    type: str
    name: str
    config_json: dict
    status: str
    status_detail: str | None
    created_at: datetime


class ConnectorTestResult(BaseModel):
    ok: bool
    message: str
    status: str


# --- Approvals ------------------------------------------------------------


class ApprovalOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    run_id: uuid.UUID
    step_id: uuid.UUID | None
    status: str
    requested_tool: str
    requested_args: dict
    summary: str
    required_role: Role | None
    expires_at: datetime | None
    decided_by: uuid.UUID | None
    decided_at: datetime | None
    decision_reason: str | None
    created_at: datetime


class ApprovalDecision(BaseModel):
    reason: str = Field(default="", max_length=1024)


class ApprovalDecisionResponse(BaseModel):
    approval: ApprovalOut
    run_status: str


# --- Workflows ------------------------------------------------------------


class WorkflowCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    description: str = Field(default="", max_length=1024)
    definition: dict = Field(default_factory=lambda: {"nodes": [], "edges": []})
    trigger_type: str = Field(default="manual", max_length=20)
    trigger_config: dict = Field(default_factory=dict)


class WorkflowUpdate(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=255)
    description: str | None = Field(default=None, max_length=1024)
    definition: dict | None = None
    trigger_type: str | None = Field(default=None, max_length=20)
    trigger_config: dict | None = None
    is_active: bool | None = None


class WorkflowOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: uuid.UUID
    name: str
    description: str
    definition_json: dict
    trigger_type: str
    trigger_config: dict
    webhook_token: str | None
    is_active: bool
    created_at: datetime


class WorkflowCreateResponse(BaseModel):
    workflow: WorkflowOut
    webhook_url: str | None = None
    # The HMAC signing secret — shown exactly once at creation for webhook triggers.
    webhook_secret: str | None = None


class WorkflowRunRequest(BaseModel):
    input: dict = Field(default_factory=dict)
