"""Agent tool conventions — shared model for cross-client AI agent tool paths.

Each AgentTool entry defines the platform conventions that differ
between AI agent CLIs (Devin, OpenCode, Copilot, Windsurf, etc.) so
hook scripts and the setup installer can adapt without hardcoding
tool-specific paths.
"""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum


class AgentTool(Enum):
    """Supported AI agent CLI tools."""

    DEVIN = "devin"
    OPENCODE = "opencode"
    COPILOT = "copilot"
    WINDSURF = "windsurf"

    @classmethod
    def from_env(cls, key: str = "AGENTS_TOOL", default: AgentTool | None = None) -> AgentTool | None:
        """Resolve an AgentTool from an environment variable."""
        import os

        raw = os.environ.get(key, "")
        if not raw:
            return default
        try:
            return cls(raw.lower())
        except ValueError:
            return default


@dataclass(frozen=True)
class ToolConventions:
    """Platform conventions for a single AI agent CLI tool.

    Attributes:
        project_config_dir: The hidden directory name the tool uses in
            project roots (e.g. ".devin", ".opencode").  Hook scripts
            look for config files under this directory.
        global_config_dir_name: Directory name under ~/.config/ for
            global user configuration (e.g. "devin" -> ~/.config/devin).
        script_path_prefix: Relative-path prefix used in hook command
            definitions pointing at the scripts/ directory inside the
            project config dir (e.g. ".devin/scripts/").
    """

    project_config_dir: str
    global_config_dir_name: str
    script_path_prefix: str


# ── tool convention registry ──────────────────────────────────────────

TOOL_CONVENTIONS: dict[AgentTool, ToolConventions] = {
    AgentTool.DEVIN: ToolConventions(
        project_config_dir=".devin",
        global_config_dir_name="devin",
        script_path_prefix=".devin/scripts/",
    ),
    AgentTool.OPENCODE: ToolConventions(
        project_config_dir=".opencode",
        global_config_dir_name="opencode",
        script_path_prefix=".agents/scripts/",
    ),
    AgentTool.COPILOT: ToolConventions(
        project_config_dir=".github",
        global_config_dir_name="copilot",
        script_path_prefix=".agents/scripts/",
    ),
    AgentTool.WINDSURF: ToolConventions(
        project_config_dir=".windsurf",
        global_config_dir_name="windsurf",
        script_path_prefix=".agents/scripts/",
    ),
}

# Default tool when none is explicitly selected.
DEFAULT_TOOL = AgentTool.DEVIN


def get_conventions(tool: AgentTool | str | None = None) -> ToolConventions:
    """Look up ToolConventions for *tool*, falling back to DEFAULT_TOOL."""
    if tool is None:
        tool = DEFAULT_TOOL
    if isinstance(tool, str):
        try:
            tool = AgentTool(tool.lower())
        except ValueError:
            return TOOL_CONVENTIONS[DEFAULT_TOOL]
    return TOOL_CONVENTIONS.get(tool, TOOL_CONVENTIONS[DEFAULT_TOOL])


def resolve_project_dir(tool: AgentTool | str | None = None) -> str:
    """Return the project-level hidden directory name for *tool*."""
    return get_conventions(tool).project_config_dir


def resolve_global_config_dir_name(tool: AgentTool | str | None = None) -> str:
    """Return the ~/.config/<name> directory component for *tool*."""
    return get_conventions(tool).global_config_dir_name
