"""Tests for brynq.knowledge_federation — Phase 66 knowledge federation."""

import json
import pytest
from pathlib import Path


@pytest.fixture(autouse=True)
def _isolate_federation(tmp_path, monkeypatch):
    """Redirect federation storage to temp directory."""
    fed_dir = tmp_path / "knowledge_fed"
    bundles_dir = fed_dir / "bundles"
    imported_dir = fed_dir / "imported"
    for d in (fed_dir, bundles_dir, imported_dir):
        d.mkdir(parents=True, exist_ok=True)
    monkeypatch.setattr("brynq.knowledge_federation.FED_DIR", fed_dir)
    monkeypatch.setattr("brynq.knowledge_federation.BUNDLES_DIR", bundles_dir)
    monkeypatch.setattr("brynq.knowledge_federation.IMPORTED_DIR", imported_dir)
    monkeypatch.setattr("brynq.knowledge_federation.SYNC_STATUS_PATH",
                        fed_dir / "sync_status.json")


@pytest.fixture
def knowledge_dir(tmp_path, monkeypatch):
    """Create a mock knowledge directory with entries."""
    kd = tmp_path / "knowledge"
    kd.mkdir()
    for i in range(3):
        entry = {
            "knowledge_id": f"k{i}",
            "topic": f"Topic {i}",
            "content": f"Content about topic {i}",
            "category": "general" if i < 2 else "architecture",
            "confidence": 0.8 + i * 0.05,
            "author_id": "agent-1",
            "created_at": "2026-01-01T00:00:00+00:00",
            "archived": False,
        }
        (kd / f"k{i}.json").write_text(json.dumps(entry), encoding="utf-8")
    # Write a dummy index
    (kd / "index.jsonl").write_text("")
    monkeypatch.setattr("brynq.knowledge_mcp.KNOWLEDGE_DIR", kd)
    return kd


# ── export_knowledge_bundle ───────────────────────────────────────────────


class TestExportBundle:
    def test_exports_all(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle
        bundle = export_knowledge_bundle()
        assert bundle["entry_count"] == 3
        assert len(bundle["entries"]) == 3

    def test_exports_by_category(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle
        bundle = export_knowledge_bundle(categories=["architecture"])
        assert bundle["entry_count"] == 1

    def test_creates_bundle_file(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle, BUNDLES_DIR
        bundle = export_knowledge_bundle()
        assert (BUNDLES_DIR / f"{bundle['bundle_id']}.json").exists()

    def test_has_content_hashes(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle
        bundle = export_knowledge_bundle()
        assert "content_hashes" in bundle
        assert len(bundle["content_hashes"]) == 3

    def test_empty_knowledge(self, monkeypatch):
        from brynq.knowledge_federation import export_knowledge_bundle
        # With no knowledge_mcp available
        monkeypatch.setattr("brynq.knowledge_federation._load_knowledge_entries",
                            lambda categories=None: [])
        bundle = export_knowledge_bundle()
        assert bundle["entry_count"] == 0


# ── import_knowledge_bundle ───────────────────────────────────────────────


class TestImportBundle:
    def test_imports_entries(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle, import_knowledge_bundle
        bundle = export_knowledge_bundle()
        result = import_knowledge_bundle(bundle, "peer-1", trust_level=0.8)
        assert result["imported"] == 3
        assert result["source_node_id"] == "peer-1"

    def test_trust_scales_confidence(self, knowledge_dir):
        from brynq.knowledge_federation import (
            export_knowledge_bundle, import_knowledge_bundle, IMPORTED_DIR
        )
        bundle = export_knowledge_bundle()
        import_knowledge_bundle(bundle, "peer-2", trust_level=0.5)
        # Check an imported entry
        files = list(IMPORTED_DIR.glob("peer-2_*.json"))
        assert len(files) >= 1
        entry = json.loads(files[0].read_text("utf-8"))
        assert entry["confidence"] <= entry["original_confidence"]

    def test_invalid_trust_level(self):
        from brynq.knowledge_federation import import_knowledge_bundle
        with pytest.raises(ValueError, match="trust_level"):
            import_knowledge_bundle({}, "p", trust_level=1.5)

    def test_empty_source_id(self):
        from brynq.knowledge_federation import import_knowledge_bundle
        with pytest.raises(ValueError, match="source_node_id"):
            import_knowledge_bundle({}, "", trust_level=0.5)

    def test_reimport_detects_conflicts(self, knowledge_dir):
        from brynq.knowledge_federation import export_knowledge_bundle, import_knowledge_bundle
        bundle = export_knowledge_bundle()
        import_knowledge_bundle(bundle, "peer-3", trust_level=0.8)
        result = import_knowledge_bundle(bundle, "peer-3", trust_level=0.9)
        assert result["conflicts_resolved"] >= 1

    def test_empty_bundle(self):
        from brynq.knowledge_federation import import_knowledge_bundle
        result = import_knowledge_bundle({"entries": []}, "peer-4")
        assert result["imported"] == 0


# ── sync_with_peer ────────────────────────────────────────────────────────


class TestSyncWithPeer:
    def test_export_sync(self, knowledge_dir):
        from brynq.knowledge_federation import sync_with_peer
        result = sync_with_peer("node-1", direction="export")
        assert "exported_entries" in result
        assert "export_bundle_id" in result

    def test_import_sync(self, knowledge_dir):
        from brynq.knowledge_federation import sync_with_peer
        result = sync_with_peer("node-2", direction="import")
        assert result["import_ready"] is True

    def test_both_sync(self, knowledge_dir):
        from brynq.knowledge_federation import sync_with_peer
        result = sync_with_peer("node-3", direction="both")
        assert "exported_entries" in result
        assert "import_ready" in result

    def test_invalid_direction(self):
        from brynq.knowledge_federation import sync_with_peer
        with pytest.raises(ValueError, match="direction"):
            sync_with_peer("x", direction="invalid")

    def test_updates_sync_status(self, knowledge_dir):
        from brynq.knowledge_federation import sync_with_peer, get_sync_status
        sync_with_peer("node-4", direction="export")
        status = get_sync_status()
        assert "node-4" in status
        assert "last_sync" in status["node-4"]


# ── get_sync_status ───────────────────────────────────────────────────────


class TestGetSyncStatus:
    def test_empty(self):
        from brynq.knowledge_federation import get_sync_status
        assert get_sync_status() == {}


# ── resolve_conflicts ─────────────────────────────────────────────────────


class TestResolveConflicts:
    def test_higher_confidence_wins(self):
        from brynq.knowledge_federation import resolve_conflicts
        local = {"content": "A", "confidence": 0.9, "updated_at": "2026-01-01"}
        remote = {"content": "B", "confidence": 0.5, "updated_at": "2026-01-02"}
        result = resolve_conflicts(local, remote)
        assert result["content"] == "A"
        assert result["conflict_resolved"] == "local_wins"

    def test_remote_wins_higher_confidence(self):
        from brynq.knowledge_federation import resolve_conflicts
        local = {"content": "A", "confidence": 0.3}
        remote = {"content": "B", "confidence": 0.8}
        result = resolve_conflicts(local, remote)
        assert result["content"] == "B"
        assert result["conflict_resolved"] == "remote_wins"

    def test_equal_confidence_recency(self):
        from brynq.knowledge_federation import resolve_conflicts
        local = {"content": "A", "confidence": 0.5, "updated_at": "2026-01-01"}
        remote = {"content": "B", "confidence": 0.5, "updated_at": "2026-01-05"}
        result = resolve_conflicts(local, remote)
        assert result["content"] == "B"
        assert "recency" in result["conflict_resolved"]

    def test_adds_resolution_timestamp(self):
        from brynq.knowledge_federation import resolve_conflicts
        result = resolve_conflicts({"confidence": 0.5}, {"confidence": 0.6})
        assert "conflict_resolved_at" in result
