"""Agent loading -- registration from config and directories."""

from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import TYPE_CHECKING

import yaml

from core.skills import get_skill_registry
from core.skills.loader import load_skills_from_directory
from core.types import AgentDefinition
from server.loaders.skills import register_skill_script_tools

if TYPE_CHECKING:
    from core.agent import AgentRepository
    from core.skills.models import Skill

logger = logging.getLogger(__name__)


async def register_agents_from_config(
    agent_specs: list[AgentDefinition],
    agent_repo: AgentRepository,
    *,
    skills_registry: dict[str, Skill] | None = None,
) -> None:
    """Register agents from deployment config.

    Parameters
    ----------
    agent_specs
        Agent definitions from the deployment config.
    agent_repo
        The agent repository to register into.
    skills_registry
        Global skills registry so agents can scope skills at boot.
    """
    count = 0
    for spec in agent_specs:
        if not spec.is_full_definition:
            continue

        # Ensure non-None name/instructions for registered agents.
        agent = spec.model_copy(
            update={
                "name": spec.display_name,
                "instructions": spec.system_prompt,
            }
        )

        if agent.id == "host":
            agent_repo.register_host(agent, skills_registry=skills_registry)
        else:
            await agent_repo.register(
                agent,
                skills_registry=skills_registry,
                agent_skills=list(agent.skills) if agent.skills else None,
            )
        count += 1
    logger.info("Registered %d agents from config", count)


async def load_agents_from_directories(
    directories: list[str],
    agent_repo: AgentRepository,
) -> int:
    """Load agent definitions from directories.

    Each subdirectory containing an ``agent.yaml`` file is treated as
    an agent package.  The agent definition is loaded from YAML and
    registered in the agent repository.  Any ``skills/`` subdirectory
    within the agent package is also scanned and its skills registered.

    Returns
    -------
        Number of agents loaded.
    """
    loaded = 0
    skill_registry = get_skill_registry()

    for dir_path in directories:
        expanded = os.path.expanduser(os.path.expandvars(dir_path))
        agents_root = Path(expanded).resolve()

        if not agents_root.exists() or not agents_root.is_dir():
            logger.warning("Agent directory does not exist: %s", dir_path)
            continue

        for agent_dir in sorted(agents_root.iterdir()):
            if not agent_dir.is_dir() or agent_dir.name.startswith((".", "_")):
                continue

            agent_yaml = agent_dir / "agent.yaml"
            if not agent_yaml.exists():
                continue

            try:
                with open(agent_yaml) as f:
                    raw = yaml.safe_load(f) or {}

                # Normalise legacy fields, then let Pydantic validate defaults.
                raw.setdefault("id", agent_dir.name)
                raw.setdefault("name", agent_dir.name.replace("-", " ").title())
                defn = AgentDefinition.from_yaml_dict(raw)

                await agent_repo.save(defn)
                loaded += 1
                logger.info("Loaded agent '%s' from %s", defn.id, agent_dir)

                skills_dir = agent_dir / "skills"
                if skills_dir.exists() and skills_dir.is_dir():
                    try:
                        skills = await load_skills_from_directory(skills_dir)
                        for skill in skills:
                            skill_registry.register(skill)
                            register_skill_script_tools(skill)
                            logger.info(
                                "  Loaded agent skill: %s (for %s)",
                                skill.id,
                                defn.id,
                            )
                    except Exception as e:
                        logger.warning(
                            "Failed to load skills for agent %s: %s",
                            defn.id,
                            e,
                        )

            except Exception as e:
                logger.warning(
                    "Failed to load agent from %s: %s",
                    agent_dir,
                    e,
                )

    if loaded:
        logger.info("Loaded %d agents from directories", loaded)
    return loaded
