"""Tests for ievo.core.agent.AgentPackage."""

from __future__ import annotations

from pathlib import Path

import pytest
import yaml

from ievo.core.agent import (
    DEFAULT_ALLOWED_TOOLS,
    AgentDisclosure,
    AgentHooks,
    AgentModel,
    AgentPackage,
    SandboxConfig,
)


def test_agent_model_defaults() -> None:
    m = AgentModel()
    assert m.primary == "sonnet"
    assert m.fallback == "haiku"


def test_agent_hooks_defaults() -> None:
    h = AgentHooks()
    assert h.on_install is None
    assert h.on_session_start == "load_memory"
    assert h.on_session_end == "save_memory"
    assert h.on_error == "evo_analyze"


def test_agent_disclosure_defaults() -> None:
    d = AgentDisclosure()
    assert d.metadata == 100
    assert d.instructions == 400
    assert d.resources == 600


def test_load_agent_package(tmp_path: Path) -> None:
    agent_yaml = {
        "name": "coder",
        "version": "0.2.0",
        "description": "TDD implementer",
        "author": "ievo-ai",
        "model": {"primary": "sonnet", "fallback": "haiku"},
        "dependencies": ["spec-writer", "architect"],
        "skills": ["ievo"],
        "hooks": {"on_error": "evo_analyze"},
    }
    (tmp_path / "agent.yaml").write_text(yaml.dump(agent_yaml, sort_keys=False))

    pkg = AgentPackage.load(tmp_path)
    assert pkg.name == "coder"
    assert pkg.version == "0.2.0"
    assert pkg.description == "TDD implementer"
    assert pkg.model.primary == "sonnet"
    assert pkg.dependencies == ["spec-writer", "architect"]
    assert pkg.skills == ["ievo"]
    assert pkg.hooks.on_error == "evo_analyze"


def test_load_missing_agent_yaml(tmp_path: Path) -> None:
    with pytest.raises(FileNotFoundError, match="agent.yaml not found"):
        AgentPackage.load(tmp_path)


def test_load_minimal_agent_yaml(tmp_path: Path) -> None:
    (tmp_path / "agent.yaml").write_text("name: minimal\n")
    pkg = AgentPackage.load(tmp_path)
    assert pkg.name == "minimal"
    assert pkg.version == "0.1.0"
    assert pkg.model.primary == "sonnet"
    assert pkg.dependencies == []
    assert pkg.skills == ["ievo"]


def test_save_agent_package(tmp_path: Path) -> None:
    pkg = AgentPackage(
        name="test-agent",
        version="1.0.0",
        description="A test agent",
        model=AgentModel(primary="opus", fallback="sonnet"),
        dependencies=["base"],
    )
    pkg.save(tmp_path)

    data = yaml.safe_load((tmp_path / "agent.yaml").read_text())
    assert data["name"] == "test-agent"
    assert data["version"] == "1.0.0"
    assert data["model"]["primary"] == "opus"
    assert data["dependencies"] == ["base"]


def test_save_creates_directory(tmp_path: Path) -> None:
    dest = tmp_path / "new" / "agent"
    pkg = AgentPackage(name="fresh")
    pkg.save(dest)
    assert (dest / "agent.yaml").exists()


def test_sandbox_config_defaults() -> None:
    s = SandboxConfig()
    assert s.allowed_tools == list(DEFAULT_ALLOWED_TOOLS)
    assert s.network is False
    assert s.memory_mb == 2048
    assert s.cpu_limit == 2.0
    assert s.timeout_seconds == 3600


def test_load_agent_with_sandbox(tmp_path: Path) -> None:
    agent_yaml = {
        "name": "coder",
        "sandbox": {
            "allowed_tools": ["Read", "Write", "Edit", "Bash", "Glob", "Grep"],
            "network": False,
            "memory_mb": 4096,
            "cpu_limit": 4.0,
            "timeout_seconds": 7200,
        },
    }
    (tmp_path / "agent.yaml").write_text(yaml.dump(agent_yaml, sort_keys=False))

    pkg = AgentPackage.load(tmp_path)
    assert pkg.sandbox.allowed_tools == ["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
    assert pkg.sandbox.network is False
    assert pkg.sandbox.memory_mb == 4096
    assert pkg.sandbox.cpu_limit == 4.0
    assert pkg.sandbox.timeout_seconds == 7200


def test_load_agent_without_sandbox_uses_defaults(tmp_path: Path) -> None:
    (tmp_path / "agent.yaml").write_text("name: minimal\n")
    pkg = AgentPackage.load(tmp_path)
    assert pkg.sandbox.allowed_tools == list(DEFAULT_ALLOWED_TOOLS)
    assert pkg.sandbox.network is False
    assert pkg.sandbox.memory_mb == 2048


def test_save_agent_includes_sandbox(tmp_path: Path) -> None:
    pkg = AgentPackage(
        name="test",
        sandbox=SandboxConfig(
            allowed_tools=["Read", "Write"],
            network=True,
            memory_mb=1024,
        ),
    )
    pkg.save(tmp_path)
    data = yaml.safe_load((tmp_path / "agent.yaml").read_text())
    assert data["sandbox"]["allowed_tools"] == ["Read", "Write"]
    assert data["sandbox"]["network"] is True
    assert data["sandbox"]["memory_mb"] == 1024


def test_save_load_roundtrip(tmp_path: Path) -> None:
    original = AgentPackage(
        name="roundtrip",
        version="2.0.0",
        description="Testing roundtrip",
        author="test",
        model=AgentModel(primary="opus", fallback="sonnet"),
        dependencies=["dep1"],
        skills=["ievo", "custom"],
        hooks=AgentHooks(on_install="setup"),
        disclosure=AgentDisclosure(metadata=200, instructions=800, resources=1200),
        sandbox=SandboxConfig(
            allowed_tools=["Read", "Write", "Bash"],
            network=True,
            memory_mb=4096,
            cpu_limit=3.0,
            timeout_seconds=1800,
        ),
    )
    original.save(tmp_path)
    loaded = AgentPackage.load(tmp_path)

    assert loaded.name == original.name
    assert loaded.version == original.version
    assert loaded.model.primary == original.model.primary
    assert loaded.model.fallback == original.model.fallback
    assert loaded.dependencies == original.dependencies
    assert loaded.skills == original.skills
    assert loaded.hooks.on_install == original.hooks.on_install
    assert loaded.disclosure.metadata == original.disclosure.metadata
    assert loaded.sandbox.allowed_tools == original.sandbox.allowed_tools
    assert loaded.sandbox.network == original.sandbox.network
    assert loaded.sandbox.memory_mb == original.sandbox.memory_mb
    assert loaded.sandbox.cpu_limit == original.sandbox.cpu_limit
    assert loaded.sandbox.timeout_seconds == original.sandbox.timeout_seconds
