from typing import Literal
from pydantic import BaseModel, Field


class Vec3(BaseModel):
    x: float
    y: float
    z: float

    def as_list(self) -> list[float]:
        return [self.x, self.y, self.z]


class JointRequest(BaseModel):
    point: Vec3
    surface_normal: Vec3 | None = None
    movement: Literal["auto", "bend", "wiggle", "rotate", "ball"] = "auto"
    requested_type: Literal["auto", "hinge", "ball_socket", "flexi"] = "auto"
    clearance_mm: float = Field(default=0.35, ge=0.1, le=1.5)
    strength_bias: float = Field(default=0.65, ge=0.0, le=1.0)


class AnalyseRequest(BaseModel):
    model_id: str
    joint: JointRequest


class ForgeRequest(BaseModel):
    model_id: str
    joint: JointRequest
    output_name: str = "flexiforge_output"
    layout_gap_mm: float = Field(default=10.0, ge=2.0, le=50.0)


class ShireCreateJobRequest(BaseModel):
    model_id: str
    project_name: str = Field(min_length=1, max_length=120)
    intent: str = Field(default="Turn this STL into an articulated fidget.", min_length=1, max_length=1000)
    movement: Literal["auto", "bend", "wiggle", "rotate", "ball"] = "auto"
    clearance_mm: float = Field(default=0.35, ge=0.1, le=1.5)
    max_suggestions: int = Field(default=5, ge=1, le=9)


class ShireSelectSuggestionRequest(BaseModel):
    suggestion_id: str
    requested_type: Literal["auto", "hinge", "ball_socket", "flexi"] = "auto"


class ApprovalTokenRequest(BaseModel):
    token: str = Field(min_length=8, max_length=160)
