"""Unit tests for timmy.vassal.backlog — triage and fetch helpers."""

from __future__ import annotations

import pytest

from timmy.vassal.backlog import (
    AgentTarget,
    _choose_agent,
    _extract_labels,
    _score_priority,
    triage_issues,
)

# ---------------------------------------------------------------------------
# _extract_labels
# ---------------------------------------------------------------------------


def test_extract_labels_empty():
    assert _extract_labels({}) == []


def test_extract_labels_normalises_case():
    issue = {"labels": [{"name": "HIGH"}, {"name": "Feature"}]}
    assert _extract_labels(issue) == ["high", "feature"]


# ---------------------------------------------------------------------------
# _score_priority
# ---------------------------------------------------------------------------


def test_priority_urgent():
    assert _score_priority(["urgent"], []) == 100


def test_priority_high():
    assert _score_priority(["high"], []) == 75


def test_priority_normal_default():
    assert _score_priority([], []) == 50


def test_priority_assigned_penalised():
    # already assigned → subtract 20
    score = _score_priority([], ["some-agent"])
    assert score == 30


def test_priority_label_substring_match():
    # "critical" contains "critical" → 90
    assert _score_priority(["critical-bug"], []) == 90


# ---------------------------------------------------------------------------
# _choose_agent
# ---------------------------------------------------------------------------


def test_choose_claude_for_architecture():
    target, rationale = _choose_agent("Refactor auth middleware", "", [])
    assert target == AgentTarget.CLAUDE
    assert "complex" in rationale or "high-complexity" in rationale


def test_choose_kimi_for_research():
    target, rationale = _choose_agent("Deep research on embedding models", "", [])
    assert target == AgentTarget.KIMI


def test_choose_timmy_for_docs():
    target, rationale = _choose_agent("Update documentation for CLI", "", [])
    assert target == AgentTarget.TIMMY


def test_choose_timmy_default():
    target, rationale = _choose_agent("Fix typo in README", "simple change", [])
    # Could route to timmy (docs/trivial) or default — either is valid
    assert isinstance(target, AgentTarget)


def test_choose_agent_label_wins():
    # "security" label → Claude
    target, _ = _choose_agent("Login page", "", ["security"])
    assert target == AgentTarget.CLAUDE


# ---------------------------------------------------------------------------
# triage_issues
# ---------------------------------------------------------------------------


def _make_raw_issue(
    number: int,
    title: str,
    body: str = "",
    labels: list[str] | None = None,
    assignees: list[str] | None = None,
) -> dict:
    return {
        "number": number,
        "title": title,
        "body": body,
        "labels": [{"name": lbl} for lbl in (labels or [])],
        "assignees": [{"login": a} for a in (assignees or [])],
        "html_url": f"http://gitea/issues/{number}",
    }


def test_triage_returns_sorted_by_priority():
    issues = [
        _make_raw_issue(1, "Routine docs update", labels=["docs"]),
        _make_raw_issue(2, "Critical security issue", labels=["urgent", "security"]),
        _make_raw_issue(3, "Normal feature", labels=[]),
    ]
    triaged = triage_issues(issues)
    # Highest priority first
    assert triaged[0].number == 2
    assert triaged[0].priority_score == 100  # urgent label


def test_triage_prs_can_be_included():
    # triage_issues does not filter PRs — that's fetch_open_issues's job
    issues = [_make_raw_issue(10, "A PR-like issue")]
    triaged = triage_issues(issues)
    assert len(triaged) == 1


def test_triage_empty():
    assert triage_issues([]) == []


def test_triage_routing():
    issues = [
        _make_raw_issue(1, "Benchmark LLM backends", body="comprehensive analysis"),
        _make_raw_issue(2, "Refactor agent loader", body="architecture change"),
        _make_raw_issue(3, "Fix typo in docs", labels=["docs"]),
    ]
    triaged = {i.number: i for i in triage_issues(issues)}

    assert triaged[1].agent_target == AgentTarget.KIMI
    assert triaged[2].agent_target == AgentTarget.CLAUDE
    assert triaged[3].agent_target == AgentTarget.TIMMY


def test_triage_preserves_url():
    issues = [_make_raw_issue(42, "Some issue")]
    triaged = triage_issues(issues)
    assert triaged[0].url == "http://gitea/issues/42"


# ---------------------------------------------------------------------------
# fetch_open_issues — no Gitea available in unit tests
# ---------------------------------------------------------------------------


@pytest.mark.asyncio
async def test_fetch_open_issues_returns_empty_when_disabled(monkeypatch):
    """When Gitea is disabled, fetch returns [] without raising."""
    import timmy.vassal.backlog as bl

    # Patch settings
    class FakeSettings:
        gitea_enabled = False
        gitea_token = ""
        gitea_url = "http://localhost:3000"
        gitea_repo = "owner/repo"

    monkeypatch.setattr(bl, "logger", bl.logger)  # no-op just to confirm import

    # We can't easily monkeypatch `from config import settings` inside the function,
    # so test the no-token path via environment
    import os

    original = os.environ.pop("GITEA_TOKEN", None)
    try:
        result = await bl.fetch_open_issues()
        # Should return [] gracefully (no token configured by default in test env)
        assert isinstance(result, list)
    finally:
        if original is not None:
            os.environ["GITEA_TOKEN"] = original
