import base64
import json

from dobby.core.collector import Collector


def test_parse_dobby_result_block():
    output = '''Some agent output here...
---DOBBY_RESULT---
{
  "status": "completed",
  "summary": "Added warmup scheduler",
  "pr_url": "https://github.com/user/repo/pull/42",
  "files_changed": ["train.py", "config.py"],
  "metrics": {"final_loss": 0.34},
  "error": null
}
---END_DOBBY_RESULT---
'''
    result = Collector.parse_output(output, exit_code=0, task_id="t-001")
    assert result.status == "completed"
    assert result.summary == "Added warmup scheduler"
    assert result.metrics == {"final_loss": 0.34}
    assert any(a.type == "pr" for a in result.artifacts)


def test_parse_output_json_format():
    """When --output-format json is used, Claude Code wraps output in JSON."""
    cc_output = json.dumps({
        "result": (
            "---DOBBY_RESULT---\n"
            '{"status": "completed", "summary": "Done", "pr_url": null,'
            ' "files_changed": [], "metrics": {}, "error": null}'
            "\n---END_DOBBY_RESULT---"
        ),
        "cost_usd": 0.42,
        "input_tokens": 45000,
        "output_tokens": 12000,
    })
    result = Collector.parse_output(cc_output, exit_code=0, task_id="t-002")
    assert result.status == "completed"
    assert result.cost["cost_usd"] == 0.42
    assert result.cost["input_tokens"] == 45000


def test_fallback_heuristic_success():
    output = "I've completed the task. Created PR at https://github.com/user/repo/pull/99"
    result = Collector.parse_output(output, exit_code=0, task_id="t-003")
    assert result.status == "completed"
    assert any((a.url or "").endswith("pull/99") for a in result.artifacts)


def test_fallback_heuristic_failure():
    output = "Error: could not find file train.py"
    result = Collector.parse_output(output, exit_code=1, task_id="t-004")
    assert result.status == "failed"
    assert "Error" in result.summary


def test_parse_gpu_phase1_result():
    output = '''---DOBBY_RESULT---
{
  "status": "completed",
  "summary": "Training launched",
  "pr_url": null,
  "files_changed": [],
  "metrics": {"gpu_pid": 12345, "log_path": "/home/user/train.log"},
  "error": null
}
---END_DOBBY_RESULT---'''
    result = Collector.parse_output(output, exit_code=0, task_id="t-005")
    assert result.metrics["gpu_pid"] == 12345
    assert result.metrics["log_path"] == "/home/user/train.log"


def test_empty_output_failure():
    result = Collector.parse_output("", exit_code=1, task_id="t-006")
    assert result.status == "failed"
    assert result.summary != ""


def _b64(text: str) -> str:
    """Encode text to base64."""
    return base64.b64encode(text.encode()).decode()


def test_parse_codex_jsonl_with_dobby_result():
    """Codex JSONL output with base64-encoded content containing DOBBY_RESULT."""
    dobby_block = (
        '---DOBBY_RESULT---\n'
        '{"status": "completed", "summary": "Implemented feature X", '
        '"pr_url": "https://github.com/user/repo/pull/7", '
        '"files_changed": ["main.py"], "metrics": {"lines_added": 42}, '
        '"error": null}\n'
        '---END_DOBBY_RESULT---'
    )
    lines = [
        json.dumps({"id": "0", "msg": {"type": "agent", "message": _b64("Starting work...\n")}}),
        json.dumps({"id": "1", "msg": {"type": "agent", "message": _b64("Editing files...\n")}}),
        json.dumps({"id": "2", "msg": {"type": "agent", "message": _b64(dobby_block)}}),
    ]
    output = "\n".join(lines)

    result = Collector.parse_output(output, exit_code=0, task_id="t-codex-1")
    assert result.status == "completed"
    assert result.summary == "Implemented feature X"
    assert result.metrics == {"lines_added": 42}
    assert any((a.url or "").endswith("pull/7") for a in result.artifacts)


def test_parse_codex_jsonl_heuristic_fallback():
    """Codex JSONL without DOBBY_RESULT falls back to heuristic on decoded text."""
    lines = [
        json.dumps({"id": "0", "msg": {
            "type": "agent", "message": _b64("All done, no issues found.\n"),
        }}),
        json.dumps({"id": "1", "msg": {"type": "status", "message": ""}}),
    ]
    output = "\n".join(lines)

    result = Collector.parse_output(output, exit_code=0, task_id="t-codex-2")
    assert result.status == "completed"
    assert "All done" in result.summary


def test_parse_codex_jsonl_with_raw_message():
    """Codex JSONL where a message is not valid base64 — should use it as raw text."""
    dobby_block = (
        '---DOBBY_RESULT---\n'
        '{"status": "completed", "summary": "Raw msg test", '
        '"pr_url": null, "files_changed": [], "metrics": {}, "error": null}\n'
        '---END_DOBBY_RESULT---'
    )
    lines = [
        json.dumps({"id": "0", "msg": {"type": "agent", "message": dobby_block}}),
    ]
    output = "\n".join(lines)

    result = Collector.parse_output(output, exit_code=0, task_id="t-codex-3")
    assert result.status == "completed"
    assert result.summary == "Raw msg test"


def test_codex_jsonl_not_triggered_for_plain_text():
    """Plain text output should NOT be detected as Codex JSONL."""
    output = "Just a normal agent output line"
    result = Collector.parse_output(output, exit_code=0, task_id="t-plain")
    assert result.status == "completed"
    assert result.summary == output
