"""Profile: the central platform artifact — declares what one agent is.

Stages add fields here as new capabilities come online. Stage 1 needed
the four basic fields; stage 3 adds `skill_source` for the `skill` tool.
"""

from pathlib import Path
from typing import Literal

from pydantic import BaseModel, Field

ToolName = Literal["exec", "skill", "exec_service", "ask_question"]


# === Skill sources ===========================================================
#
# A SkillSource describes WHERE the agent's procedure files live. Stage 3
# ships one implementation — LocalSkillSource — but real production
# deployments will want one of:
#
#   GitRepoSkillSource(repo_url=..., ref=..., authorization_header=...)
#       Clone a versioned skill repo into a tempdir at flow start. The
#       prod path: skills are code-reviewed via PRs, shared across
#       teammates and running agents.
#
#   InlineMarkdownSkillSource(name=..., markdown=...)
#       Bake the markdown text directly into the Profile. Useful for
#       one-off agents, tests, or skills generated by another flow.
#
#   <YourCustom>SkillSource(...)
#       Object storage (S3 / GCS), kitaru artifacts, container-image bake.
#
# Adding a new source = subclass `LocalSkillSource`'s shape: a
# `resolve(self) -> Path` returning a host-readable directory of
# markdown files. The skill tool itself doesn't change.
#
# This example only ships LocalSkillSource. Fork to add the variant
# your team needs.


class LocalSkillSource(BaseModel):
    """Skills loaded from a host-side directory the operator edits in their IDE.

    Right shape for local development and the stage 3 example. For
    production, see the comment above for the prod-shaped alternatives.
    """

    type: Literal["local"] = "local"
    path: str

    def resolve(self) -> Path:
        return Path(self.path).resolve()


# Forks extend this union (e.g. `LocalSkillSource | GitRepoSkillSource`).
SkillSource = LocalSkillSource


class SandboxProxyRule(BaseModel):
    """Tell the credential proxy: when the worker requests one of `hosts`,
    inject `headers` into the request.

    Header values can contain `{{ secret-name.key }}` templates that
    resolve at flow start via `kitaru.get_secret(...)` — the worker
    container itself never sees the resolved value.
    """

    name: str
    hosts: list[str]
    headers: dict[str, str]


class Profile(BaseModel):
    """One agent's runtime profile."""

    name: str
    system_prompt: str
    model: str  # raw pydantic-ai provider string, e.g. "openai:gpt-4o-mini"
    allowed_tools: set[ToolName] = Field(default_factory=set)
    # Where the `skill` tool reads procedure files from. None = no skills.
    skill_source: SkillSource | None = None
    # Per-host header injection rules. Headers can contain
    # `{{ secret-name.key }}` templates resolved via kitaru.secrets.
    sandbox_proxy_rules: list[SandboxProxyRule] = Field(default_factory=list)
    # Names of services (keys of `agent_harness_platform.services.ALL_SERVICES`)
    # the agent is allowed to call via `exec_service`. Empty = `exec_service`
    # is enabled but the agent has no services to dispatch to (mostly
    # useful for tests).
    allowed_services: set[str] = Field(default_factory=set)
