"""Tests for dobby.core.introspect — agent log parsing for detail-status."""
import json

from dobby.core.introspect import DetailStatus, parse_agent_log


def test_empty_log():
    ds = parse_agent_log("", "t-123", "running")
    assert ds.task_id == "t-123"
    assert ds.status == "running"
    assert ds.current_activity == ""
    assert ds.files_touched == []
    assert ds.tools_used == {}
    assert ds.tokens == {}
    assert ds.lines_parsed == 0


def test_tool_counting():
    log = "\n".join([
        "Using Read tool on src/main.py",
        "Using Edit tool on src/main.py",
        "Using Edit tool on src/utils.py",
        "Using Bash tool to run tests",
        "Using Grep tool for search",
        "Using Glob tool for files",
    ])
    ds = parse_agent_log(log, "t-abc", "running")
    assert ds.tools_used["Read"] == 1
    assert ds.tools_used["Edit"] == 2
    assert ds.tools_used["Bash"] == 1
    assert ds.tools_used["Grep"] == 1
    assert ds.tools_used["Glob"] == 1


def test_file_extraction():
    log = "\n".join([
        'Editing file "src/main.py"',
        "Reading ./tests/test_foo.py for context",
        "Writing to dobby/core/api.py",
    ])
    ds = parse_agent_log(log, "t-abc", "running")
    # Should find file references
    assert any("main.py" in f for f in ds.files_touched)
    assert any("test_foo.py" in f for f in ds.files_touched)
    assert any("api.py" in f for f in ds.files_touched)


def test_file_deduplication():
    log = "\n".join([
        "Read src/main.py",
        "Edit src/main.py",
        "Read src/main.py again",
    ])
    ds = parse_agent_log(log, "t-abc", "running")
    # src/main.py should appear only once
    count = sum(1 for f in ds.files_touched if f == "src/main.py")
    assert count == 1


def test_current_activity_last_line():
    log = "\n".join([
        "Starting task",
        "Using Read tool on foo.py",
        "Using Edit tool on bar.py",
        "All tests passed successfully",
    ])
    ds = parse_agent_log(log, "t-abc", "running")
    # Current activity should be from the last meaningful line
    assert "tests passed" in ds.current_activity.lower() or "Edit" in ds.current_activity


def test_json_token_extraction():
    envelope = {
        "type": "result",
        "subtype": "success",
        "num_turns": 15,
        "duration_ms": 120000,
        "total_cost_usd": 0.85,
        "usage": {
            "input_tokens": 1000,
            "output_tokens": 500,
            "cache_read_input_tokens": 5000,
        },
        "modelUsage": {
            "claude-opus-4-6[1m]": {
                "inputTokens": 100,
                "outputTokens": 500,
                "cacheReadInputTokens": 5000,
                "cacheCreationInputTokens": 900,
            }
        },
    }
    log = json.dumps(envelope)
    ds = parse_agent_log(log, "t-abc", "completed")
    assert ds.tokens["cost_usd"] == 0.85
    assert ds.tokens["num_turns"] == 15
    assert ds.tokens["duration_ms"] == 120000
    assert ds.tokens["input_tokens"] == 1000
    assert ds.tokens["output_tokens"] == 500
    assert ds.tokens["total_tokens"] == 5000 + 100 + 500


def test_non_json_log():
    log = "\n".join([
        "Starting agent...",
        "Exploring codebase",
        "Found 5 files matching pattern",
    ])
    ds = parse_agent_log(log, "t-abc", "running")
    assert ds.tokens == {}
    assert ds.lines_parsed == 3


def test_lines_parsed_capped_at_100():
    log = "\n".join([f"Line {i}" for i in range(200)])
    ds = parse_agent_log(log, "t-abc", "running")
    assert ds.lines_parsed == 100


def test_to_dict():
    ds = DetailStatus(
        task_id="t-abc",
        status="running",
        current_activity="Editing file",
        files_touched=["src/main.py"],
        tools_used={"Edit": 2, "Read": 1},
        tokens={"cost_usd": 0.5},
        lines_parsed=10,
    )
    d = ds.to_dict()
    assert d["task_id"] == "t-abc"
    assert d["status"] == "running"
    assert d["current_activity"] == "Editing file"
    assert d["files_touched"] == ["src/main.py"]
    assert d["tools_used"] == {"Edit": 2, "Read": 1}
    assert d["tokens"] == {"cost_usd": 0.5}
    assert d["lines_parsed"] == 10


def test_mixed_log_with_tools_and_files():
    """Simulate a realistic agent log snippet."""
    log = "\n".join([
        "Agent starting task for project dobby",
        "Using Read tool to read dobby/core/api.py",
        "File has 350 lines",
        "Using Grep tool to search for patterns",
        "Found 3 matches",
        "Using Edit tool on dobby/core/api.py to add endpoint",
        "Using Write tool to create tests/test_new.py",
        "Using Bash tool to run: pytest tests/",
        "PASS: 42 tests passed",
        "Using Edit tool on dobby/models.py to add field",
        "Committing changes via git commit",
    ])
    ds = parse_agent_log(log, "t-test", "running")

    assert ds.tools_used.get("Read", 0) >= 1
    assert ds.tools_used.get("Grep", 0) >= 1
    assert ds.tools_used.get("Edit", 0) >= 2
    assert ds.tools_used.get("Write", 0) >= 1
    assert ds.tools_used.get("Bash", 0) >= 1

    assert any("api.py" in f for f in ds.files_touched)
    assert any("test_new.py" in f for f in ds.files_touched)
    assert any("models.py" in f for f in ds.files_touched)

    # Last activity should relate to commit or last edit
    assert ds.current_activity != ""
