"""
Studio workflow editor data models.
"""
from __future__ import annotations

from enum import Enum
from typing import Any, Dict, List, Literal, Optional

from pydantic import BaseModel, Field


class DisplayParam(BaseModel):
    key: str
    label: str
    type: str = "text"
    required: bool = True
    placeholder: str = ""


class InputRef(BaseModel):
    ref: str
    label: Optional[str] = None
    optional: bool = False


class ScoringDimension(BaseModel):
    id: str
    name: str
    criteria: str = ""


class InsertionRagConfig(BaseModel):
    libraryId: str = ""
    threshold: float = 0.5
    maxEntries: int = 3


class InsertionConfig(BaseModel):
    position: int = 1
    activationType: str = "permanent"
    key: str = ""
    keysecondary: str = ""
    comment: str = ""
    ragConfig: Optional[InsertionRagConfig] = None


class ScoringConfig(BaseModel):
    enabled: bool = True
    dimensions: List[ScoringDimension] = Field(default_factory=list)
    rubric: Optional[str] = None


class StudioNode(BaseModel):
    id: str
    skillId: str
    displayName: str
    enabled: bool = True
    niche: Optional[str] = None
    loopUntilSatisfied: bool = False
    config: Dict[str, Any] = Field(default_factory=dict)
    displayParams: List[DisplayParam] = Field(default_factory=list)
    inputs: List[InputRef] = Field(default_factory=list)


class PipelineDefinition(BaseModel):
    workflowGoal: str = ""
    nodes: List[StudioNode] = Field(default_factory=list)


class StudioProjectMeta(BaseModel):
    id: str
    name: str
    description: str = ""
    templateId: Optional[str] = None
    characterId: Optional[str] = None
    worldbookId: Optional[str] = None
    createdAt: str = ""
    updatedAt: str = ""


class StudioProject(BaseModel):
    meta: StudioProjectMeta
    pipeline: PipelineDefinition


class ArtifactDef(BaseModel):
    type: str
    displayName: str = ""


class SkillTemplateDef(BaseModel):
    skillId: str
    displayName: str
    description: str = ""
    displayParams: List[DisplayParam] = Field(default_factory=list)
    configWhitelist: List[str] = Field(default_factory=list)
    artifacts: List[ArtifactDef] = Field(default_factory=list)
    supportsLoopUntilSatisfied: bool = False
    supportsInputs: bool = False
    supportsInsertion: bool = False
    supportsScoring: bool = False


class WorkflowTemplateSummary(BaseModel):
    id: str
    name: str
    description: str = ""


class WorkflowVariableDef(BaseModel):
    ref: str
    label: str
    description: str = ""


class DynamicVariableSuffix(BaseModel):
    suffix: str
    labelPattern: str


class WorkflowVariablesResponse(BaseModel):
    builtIn: List[WorkflowVariableDef] = Field(default_factory=list)
    dynamic: List[WorkflowVariableDef] = Field(default_factory=list)


class SkillTemplatesCatalog(BaseModel):
    templates: List[SkillTemplateDef] = Field(default_factory=list)


class StudioProjectSummary(BaseModel):
    id: str
    name: str
    description: str = ""
    updatedAt: str = ""


class CreateStudioProjectRequest(BaseModel):
    name: str = "新项目"
    template_id: str = "builtin.studio.example"
    project_id: Optional[str] = None


class UpdateStudioProjectRequest(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=120)
    description: Optional[str] = Field(None, max_length=500)


class StudioRunStatus(str, Enum):
    PENDING = "pending"
    RUNNING = "running"
    PAUSED = "paused"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class ToolQuestionOption(BaseModel):
    question: str
    options: List[str] = Field(default_factory=list)


class StepMessage(BaseModel):
    """Short step-scoped dialogue (not full chat history)."""
    id: str
    role: str  # user | assistant
    content: str
    createdAt: Optional[str] = None


class LastToolResponse(BaseModel):
    """LLM tool-call payload surfaced to the run UI (R2+)."""
    thinking: Optional[str] = None
    evaluation: Optional[str] = None
    questions: List[ToolQuestionOption] = Field(default_factory=list)
    generatedAt: Optional[str] = None


class PromptBlock(BaseModel):
    """Single assembled context section for LLM prompt (R2 debug / execution)."""
    id: str
    label: str
    content: str
    source: str = "auto"  # auto | manual | workflow


class TurnSnapshot(BaseModel):
    """State captured before each LLM turn (for undo)."""
    lastDraft: Optional[Dict[str, Any]] = None
    lastToolResponse: Optional[LastToolResponse] = None
    stepMessages: List[StepMessage] = Field(default_factory=list)
    timestamp: Optional[str] = None


class StudioNodeRunState(BaseModel):
    nodeId: str
    displayName: str
    skillId: str
    status: str  # pending | active | completed | skipped
    loopUntilSatisfied: bool = False
    lastDraft: Optional[Dict[str, Any]] = None
    lastToolResponse: Optional[LastToolResponse] = None
    stepMessages: List[StepMessage] = Field(default_factory=list)
    turnHistory: List[TurnSnapshot] = Field(default_factory=list)


class StudioRun(BaseModel):
    id: str
    projectId: str
    status: StudioRunStatus
    pipelineSnapshot: PipelineDefinition
    pipelineVersionNote: str
    currentNodeId: Optional[str] = None
    nodeStates: List[StudioNodeRunState] = Field(default_factory=list)
    workflowVariables: Dict[str, Any] = Field(default_factory=dict)
    lastPromptBlocks: List[PromptBlock] = Field(default_factory=list)
    title: str = ""
    createdAt: str = ""
    updatedAt: str = ""


class AdvanceRunRequest(BaseModel):
    displayParams: Dict[str, str] = Field(default_factory=dict)
    saveMode: Literal["advance", "append", "overwrite"] = "advance"


class SaveRunRequest(BaseModel):
    mode: Literal["incremental", "overwrite"]


class SwitchRunNodeRequest(BaseModel):
    nodeId: str = Field(..., min_length=1)


class RunMessageRequest(BaseModel):
    content: str = Field(..., min_length=1, max_length=32000)
    stream: bool = False
    profileId: Optional[str] = None
    apiConfig: Optional[Dict[str, str]] = None


class RunRerollRequest(BaseModel):
    stream: bool = False
    profileId: Optional[str] = None
    apiConfig: Optional[Dict[str, str]] = None


class RenameRunRequest(BaseModel):
    title: str = Field(..., min_length=1, max_length=120)


class StudioRunSummary(BaseModel):
    id: str
    projectId: str
    status: StudioRunStatus
    currentNodeId: Optional[str] = None
    title: str = ""
    createdAt: str = ""
    updatedAt: str = ""
