"""Tests for agentbyte.cli create-skills command."""

from __future__ import annotations

import argparse
from pathlib import Path
from unittest.mock import patch

import pytest

from agentbyte.cli.main import cmd_create_skills, _PROVIDER_TARGET, _interactive_wizard


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _make_args(provider: str = "github-copilot") -> argparse.Namespace:
    return argparse.Namespace(provider=provider)


# ---------------------------------------------------------------------------
# Tests: create-skills — github-copilot
# ---------------------------------------------------------------------------

def test_create_skills_github_copilot_writes_files(tmp_path: Path, monkeypatch):
    """Skills are written to .github/skills/ when provider=github-copilot."""
    monkeypatch.setattr("builtins.input", lambda _: "y")
    args = _make_args("github-copilot")
    rc = cmd_create_skills(args, cwd=tmp_path)

    assert rc == 0
    dest = tmp_path / ".github" / "skills"
    assert dest.is_dir(), "Target directory was not created"

    # Spot-check one well-known skill
    skill_file = dest / "agentbyte-simple-agent" / "SKILL.md"
    assert skill_file.exists(), f"Expected skill file missing: {skill_file}"
    assert skill_file.stat().st_size > 0, "Skill file is empty"


def test_create_skills_claude_writes_files(tmp_path: Path, monkeypatch):
    """Skills are written to .claude/skills/ when provider=claude."""
    monkeypatch.setattr("builtins.input", lambda _: "y")
    args = _make_args("claude")
    rc = cmd_create_skills(args, cwd=tmp_path)

    assert rc == 0
    dest = tmp_path / ".claude" / "skills"
    assert dest.is_dir(), "Target directory was not created"


def test_create_skills_abort_on_no(tmp_path: Path, monkeypatch):
    """Answering 'n' writes no files."""
    monkeypatch.setattr("builtins.input", lambda _: "n")
    args = _make_args("github-copilot")
    rc = cmd_create_skills(args, cwd=tmp_path)

    assert rc == 0
    dest = tmp_path / ".github" / "skills"
    assert not dest.exists(), "No files should be written when user declines"


def test_create_skills_abort_on_empty_input(tmp_path: Path, monkeypatch):
    """Pressing Enter (empty string) is treated as 'no'."""
    monkeypatch.setattr("builtins.input", lambda _: "")
    args = _make_args("github-copilot")
    rc = cmd_create_skills(args, cwd=tmp_path)

    assert rc == 0
    dest = tmp_path / ".github" / "skills"
    assert not dest.exists()


def test_create_skills_overwrite_marker_shown(tmp_path: Path, monkeypatch, capsys):
    """When a skill already exists, the preview shows [overwrite]."""
    # Pre-create one skill file so the overwrite marker appears
    existing = tmp_path / ".github" / "skills" / "agentbyte-simple-agent" / "SKILL.md"
    existing.parent.mkdir(parents=True, exist_ok=True)
    existing.write_text("old content")

    monkeypatch.setattr("builtins.input", lambda _: "n")  # abort after preview
    args = _make_args("github-copilot")
    cmd_create_skills(args, cwd=tmp_path)

    captured = capsys.readouterr()
    assert "[overwrite]" in captured.out


def test_create_skills_all_skills_bundled(tmp_path: Path, monkeypatch):
    """All expected skill directories are present in the bundle."""
    expected_skills = {
        "agentbyte-agent-as-tool",
        "agentbyte-ai-driven-orchestration",
        "agentbyte-dataset",
        "agentbyte-fastapi-sse-streaming",
        "agentbyte-function-tools",
        "agentbyte-handoff-orchestration",
        "agentbyte-list-memory",
        "agentbyte-llm-client",
        "agentbyte-memory-tool",
        "agentbyte-middleware",
        "agentbyte-multi-turn-context",
        "agentbyte-otel-tracing",
        "agentbyte-plan-based-orchestration",
        "agentbyte-round-robin-orchestration",
        "agentbyte-simple-agent",
        "agentbyte-tool-approval",
        "agentbyte-workflow",
        "skill-authoring",
    }

    monkeypatch.setattr("builtins.input", lambda _: "y")
    args = _make_args("github-copilot")
    cmd_create_skills(args, cwd=tmp_path)

    dest = tmp_path / ".github" / "skills"
    written_dirs = {d.name for d in dest.iterdir() if d.is_dir()}
    assert expected_skills == written_dirs


# ---------------------------------------------------------------------------
# Tests: provider target mapping
# ---------------------------------------------------------------------------

def test_provider_target_mapping():
    assert _PROVIDER_TARGET["github-copilot"] == Path(".github") / "skills"
    assert _PROVIDER_TARGET["claude"] == Path(".claude") / "skills"


# ---------------------------------------------------------------------------
# Tests: CLI entry-point (argparse integration)
# ---------------------------------------------------------------------------

def test_main_no_args_launches_wizard(monkeypatch, capsys):
    """Running agentbyte with no args launches the interactive wizard."""
    from agentbyte.cli.main import main

    # Select command 1 (create-skills), provider 1 (github-copilot), then abort copy
    inputs = iter(["1", "1", "n"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    with pytest.raises(SystemExit) as exc_info:
        with patch("sys.argv", ["agentbyte"]):
            main()
    assert exc_info.value.code == 0
    out = capsys.readouterr().out
    assert "create-skills" in out
    assert "github-copilot" in out


def test_main_version(capsys):
    """--version prints the version string."""
    from agentbyte.cli.main import main
    from agentbyte.__about__ import VERSION

    with pytest.raises(SystemExit) as exc_info:
        with patch("sys.argv", ["agentbyte", "--version"]):
            main()
    assert exc_info.value.code == 0
    assert VERSION in capsys.readouterr().out


# ---------------------------------------------------------------------------
# Tests: interactive wizard
# ---------------------------------------------------------------------------

def test_wizard_selects_github_copilot(tmp_path: Path, monkeypatch):
    """Wizard: choosing 1/1 selects github-copilot and runs create-skills."""
    # command=1 (create-skills), provider=1 (github-copilot), copy=y
    inputs = iter(["1", "1", "y"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    rc = _interactive_wizard()
    assert rc == 0


def test_wizard_selects_claude(tmp_path: Path, monkeypatch, capsys):
    """Wizard: choosing 1/2 selects claude provider."""
    # command=1 (create-skills), provider=2 (claude), abort copy
    inputs = iter(["1", "2", "n"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    rc = _interactive_wizard()
    assert rc == 0
    assert "claude" in capsys.readouterr().out


def test_wizard_default_on_empty_input(monkeypatch, capsys):
    """Wizard: pressing Enter defaults to option 1 at every prompt."""
    # Empty = default (1) for both command and provider, then abort
    inputs = iter(["", "", "n"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    rc = _interactive_wizard()
    assert rc == 0
    out = capsys.readouterr().out
    assert "github-copilot" in out


def test_wizard_invalid_command_then_valid(monkeypatch):
    """Wizard: one invalid command choice re-prompts, then valid choice proceeds."""
    # "9" is invalid → re-prompt → "1" selects create-skills → "1" provider → abort
    inputs = iter(["9", "1", "1", "n"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    rc = _interactive_wizard()
    assert rc == 0


def test_wizard_invalid_command_twice_aborts(monkeypatch):
    """Wizard: two invalid command choices aborts cleanly."""
    inputs = iter(["9", "9"])
    monkeypatch.setattr("builtins.input", lambda _: next(inputs))

    rc = _interactive_wizard()
    assert rc == 0


def test_wizard_abort_on_keyboard_interrupt(monkeypatch):
    """Wizard: KeyboardInterrupt at command prompt aborts cleanly."""
    monkeypatch.setattr("builtins.input", lambda _: (_ for _ in ()).throw(KeyboardInterrupt))

    rc = _interactive_wizard()
    assert rc == 0
