from types import SimpleNamespace

from deerflow.agents.middlewares.artifact_reconcile_middleware import (
    ArtifactReconcileMiddleware,
)
from deerflow.agents.thread_state import ARTIFACTS_REPLACE_SENTINEL


def test_before_model_prunes_missing_outputs_artifacts(tmp_path):
    outputs_dir = tmp_path / "outputs"
    outputs_dir.mkdir()
    existing = outputs_dir / "keep.md"
    existing.write_text("ok", encoding="utf-8")

    middleware = ArtifactReconcileMiddleware()
    state = {
        "thread_data": {"outputs_path": str(outputs_dir)},
        "artifacts": [
            "/mnt/user-data/outputs/keep.md",
            "/mnt/user-data/outputs/missing.md",
        ],
    }

    result = middleware.before_model(state, runtime=SimpleNamespace(context={}))

    assert result == {
        "artifacts": [ARTIFACTS_REPLACE_SENTINEL, "/mnt/user-data/outputs/keep.md"]
    }


def test_before_model_returns_none_when_no_changes(tmp_path):
    outputs_dir = tmp_path / "outputs"
    outputs_dir.mkdir()
    existing = outputs_dir / "keep.md"
    existing.write_text("ok", encoding="utf-8")

    middleware = ArtifactReconcileMiddleware()
    state = {
        "thread_data": {"outputs_path": str(outputs_dir)},
        "artifacts": ["/mnt/user-data/outputs/keep.md"],
    }

    result = middleware.before_model(state, runtime=SimpleNamespace(context={}))

    assert result is None


def test_before_model_adds_unpresented_outputs_files(tmp_path):
    outputs_dir = tmp_path / "outputs"
    outputs_dir.mkdir()
    existing = outputs_dir / "keep.md"
    existing.write_text("ok", encoding="utf-8")
    extra = outputs_dir / "extra.md"
    extra.write_text("ok", encoding="utf-8")

    middleware = ArtifactReconcileMiddleware()
    state = {
        "thread_data": {"outputs_path": str(outputs_dir)},
        "artifacts": ["/mnt/user-data/outputs/keep.md"],
    }

    result = middleware.before_model(state, runtime=SimpleNamespace(context={}))

    assert result == {
        "artifacts": [
            ARTIFACTS_REPLACE_SENTINEL,
            "/mnt/user-data/outputs/keep.md",
            "/mnt/user-data/outputs/extra.md",
        ]
    }


def test_before_model_discovers_outputs_when_artifacts_empty(tmp_path):
    outputs_dir = tmp_path / "outputs"
    outputs_dir.mkdir()
    report = outputs_dir / "report.md"
    report.write_text("ok", encoding="utf-8")

    middleware = ArtifactReconcileMiddleware()
    state = {
        "thread_data": {"outputs_path": str(outputs_dir)},
        "artifacts": [],
    }

    result = middleware.before_model(state, runtime=SimpleNamespace(context={}))

    assert result == {
        "artifacts": [ARTIFACTS_REPLACE_SENTINEL, "/mnt/user-data/outputs/report.md"]
    }


def test_before_model_drops_leaked_replace_sentinel(tmp_path):
    outputs_dir = tmp_path / "outputs"
    outputs_dir.mkdir()
    keep = outputs_dir / "keep.md"
    keep.write_text("ok", encoding="utf-8")

    middleware = ArtifactReconcileMiddleware()
    state = {
        "thread_data": {"outputs_path": str(outputs_dir)},
        "artifacts": [
            ARTIFACTS_REPLACE_SENTINEL,
            "/mnt/user-data/outputs/keep.md",
        ],
    }

    result = middleware.before_model(state, runtime=SimpleNamespace(context={}))

    assert result == {
        "artifacts": [ARTIFACTS_REPLACE_SENTINEL, "/mnt/user-data/outputs/keep.md"]
    }
