"""Pydantic models for exokit.

Declaration order follows the DAG: standalone models first, composites last.
"""

from __future__ import annotations

from pathlib import Path
from typing import Literal

from pydantic import BaseModel

# --- Standalone models (no dependencies) ---


class Question(BaseModel):
    """A questionnaire question definition. JSON-serializable for V2 web forms."""

    id: str
    type: Literal["text", "select", "confirm"]
    prompt: str
    required: bool = True
    default: str | None = None
    default_from: str | None = None  # Key referencing a compute function (V2-ready)
    options: list[str] | None = None  # For select type
    help_text: str | None = None


class QuestionnaireAnswers(BaseModel):
    """Raw validated answers from the user. No computed fields."""

    company: str = ""  # Optional — leave empty for generic industry demos
    industry: str
    demo_description: str  # User's intent: what kind of demo, scope, special requests
    catalog: str
    warehouse_id: str
    workspace_host: str
    databricks_profile: str | None = None
    lakebase_url: str | None = None
    notification_email: str


class ScaffoldContext(QuestionnaireAnswers):
    """Answers + computed fields, ready for template rendering."""

    bundle_name: str  # derived: f"{company.lower()}-{industry}-demo"
    app_name: str  # derived: f"{company.lower()}-{industry}-app"


class PrereqResult(BaseModel):
    """Result of a single prerequisite check."""

    name: str
    passed: bool
    message: str
    version: str | None = None


class WaveDefinition(BaseModel):
    """A wave in the demo build plan."""

    id: int
    name: str
    status: Literal["pending", "in_progress", "completed", "skipped"] = "pending"
    components: list[str]
    description: str


class ManifestMeta(BaseModel):
    """Metadata about the generated demo."""

    company: str
    industry: str
    demo_description: str
    generated_at: str
    exokit_version: str


class SchemaDefinition(BaseModel):
    """Placeholder for table/schema definitions. Claude populates during build."""

    tables: dict[str, list[str]] = {}  # table_name -> column_names
    notes: str = ""


class Decision(BaseModel):
    """An architectural decision logged during the build."""

    summary: str
    rationale: str = ""
    decided_at: str = ""


# --- Composite models (depend on above) ---


class DemoManifest(BaseModel):
    """The demo_manifest.json schema."""

    meta: ManifestMeta
    waves: list[WaveDefinition]
    schemas: SchemaDefinition = SchemaDefinition()
    talk_track_hints: list[str] = []
    decisions: list[Decision] = []


class ScaffoldResult(BaseModel):
    """Result of the scaffold operation."""

    project_dir: Path
    files_created: list[str]
    warnings: list[str]
    manifest: DemoManifest
