"""Tests for evaluate context builders."""

from __future__ import annotations

from pathlib import Path

import pytest

from abreka.cli.agent.evaluate import (
    _build_branch_context,
    _build_global_context,
    _build_parent_context,
    _find_branch_root,
)


def _exp(eid, *, parents=None, acc=None, status="completed", created_at="2026-04-01T00:00:00+00:00"):
    e = {
        "id": eid,
        "status": status,
        "hypothesis": f"hypothesis for {eid}",
        "method": f"method for {eid}",
        "parents": parents or [],
        "tags": [],
        "created_at": created_at,
    }
    if acc is not None:
        e["metrics"] = {"val": {"accuracy": acc}}
    return e


@pytest.fixture
def abreka_dir(tmp_path: Path) -> Path:
    d = tmp_path / "abreka"
    (d / "experiments").mkdir(parents=True)
    return d


class TestFindBranchRoot:
    def test_returns_self_for_root(self):
        index = {"0001": _exp("0001")}
        assert _find_branch_root(index, "0001") == "0001"

    def test_walks_up_chain(self):
        index = {
            "0001": _exp("0001"),
            "0002": _exp("0002", parents=["0001"]),
            "0003": _exp("0003", parents=["0002"]),
        }
        assert _find_branch_root(index, "0003") == "0001"


class TestBuildParentContext:
    def test_no_parent(self, abreka_dir):
        index = {"0001": _exp("0001", acc=0.9)}
        out = _build_parent_context(index, abreka_dir, "0001", "val:accuracy", "maximize")
        assert "no parent" in out.lower()

    def test_single_parent_delta(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], acc=0.85),
        }
        out = _build_parent_context(index, abreka_dir, "0002", "val:accuracy", "maximize")
        assert "Parent 0001" in out
        assert "+0.05" in out  # delta

    def test_parent_delta_minimize(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.5),
            "0002": _exp("0002", parents=["0001"], acc=0.3),
        }
        # Using accuracy key but minimizing interpretation — treat as loss-like
        out = _build_parent_context(index, abreka_dir, "0002", "val:accuracy", "minimize")
        # Improvement = parent - child = +0.2 under minimize
        assert "+0.2" in out

    def test_includes_parent_findings(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.8),
            "0002": _exp("0002", parents=["0001"], acc=0.9),
        }
        pdir = abreka_dir / "experiments" / "0001"
        pdir.mkdir(parents=True)
        (pdir / "findings.md").write_text("Parent discovered X.")
        out = _build_parent_context(index, abreka_dir, "0002", "val:accuracy", "maximize")
        assert "Parent discovered X" in out


class TestBuildBranchContext:
    def test_renders_branch_summary(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], acc=0.85),
            "0003": _exp("0003", parents=["0002"], acc=0.90),
        }
        out = _build_branch_context(index, abreka_dir, "0003", "val:accuracy", "maximize")
        assert "Branch Summary: 0001" in out
        assert "Performance" in out


class TestBuildGlobalContext:
    def test_flags_new_global_best(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], acc=0.95),
        }
        out = _build_global_context(index, "0002", "val:accuracy", "maximize")
        assert "new global best" in out.lower()

    def test_flags_new_branch_best_when_not_global(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], acc=0.85),
            "0100": _exp("0100", acc=0.99),
        }
        out = _build_global_context(index, "0002", "val:accuracy", "maximize")
        assert "new branch best" in out.lower()

    def test_gap_to_global_when_not_best(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], acc=0.85),
            "0100": _exp("0100", acc=0.99),
        }
        out = _build_global_context(index, "0002", "val:accuracy", "maximize")
        assert "Gap to global best" in out
        assert "0.14" in out

    def test_handles_missing_metric(self, abreka_dir):
        index = {
            "0001": _exp("0001", acc=0.80),
            "0002": _exp("0002", parents=["0001"], status="running"),
        }
        out = _build_global_context(index, "0002", "val:accuracy", "maximize")
        assert "no val:accuracy recorded" in out
