"""Integration tests: write-path consistency across core modules.

Verifies that all mutation operations (INSERT, UPDATE, DELETE) across
GreyMatter core modules produce correct, persistent database state.
Covers:
- Knowledge entry write lifecycle (create, update, confirm, flag_stale, prune, auto_archive)
- Pattern write lifecycle (create, add_evidence, confidence escalation, delete)
- Session checkpoint and state management writes
- Work item status transition writes
- Document store write persistence
- Quality engine merge_duplicates writes
- Cross-module lineage writes (knowledge ↔ observations, patterns ↔ observations)
- Idempotency and concurrent write safety
"""

import sqlite3
from datetime import datetime, timedelta, timezone

import pytest

from greymatter_core.db import SQLiteDatabase
from greymatter_core.documents import DocumentStore
from greymatter_core.knowledge import KnowledgeStore
from greymatter_core.patterns import PatternManager
from greymatter_core.quality import QualityEngine
from greymatter_core.sessions import SessionManager
from greymatter_core.soul import SoulManager
from greymatter_core.work_items import WorkItemManager


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


@pytest.fixture
def db():
    """Shared in-memory database for write integration tests."""
    database = SQLiteDatabase(":memory:")
    yield database
    database.close()


@pytest.fixture
def knowledge(db):
    return KnowledgeStore(db)


@pytest.fixture
def patterns(db):
    return PatternManager(db)


@pytest.fixture
def sessions(db):
    return SessionManager(db)


@pytest.fixture
def work_items(db):
    return WorkItemManager(db)


@pytest.fixture
def quality(db):
    return QualityEngine(db)


@pytest.fixture
def doc_store(db):
    return DocumentStore(db)


@pytest.fixture
def soul(tmp_path):
    return SoulManager(tmp_path / "soul" / "default.md")


# ---------------------------------------------------------------------------
# Knowledge Write Lifecycle
# ---------------------------------------------------------------------------


class TestKnowledgeWriteLifecycle:
    """Verify all knowledge_entries mutation paths persist correctly."""

    def test_create_persists_all_fields(self, db, knowledge):
        """Every field from create() is readable from the raw DB."""
        entry = knowledge.create(
            entry_type="expertise",
            title="WAL Mode",
            content="SQLite WAL allows concurrent reads",
            domain="database",
            scope="project",
            valence="positive",
            tags="sqlite,concurrency",
        )
        assert entry["id"].startswith("kn-") or entry["id"].startswith("ke-")

        # Verify via raw SQL — bypasses any caching in KnowledgeStore
        row = db.execute_one(
            "SELECT * FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row is not None
        assert row["entry_type"] == "expertise"
        assert row["title"] == "WAL Mode"
        assert row["content"] == "SQLite WAL allows concurrent reads"
        assert row["domain"] == "database"
        assert row["scope"] == "project"
        assert row["valence"] == "positive"
        assert row["tags"] == "sqlite,concurrency"
        assert row["pruned_at"] is None
        assert row["stale_flagged_at"] is None
        assert row["applied_count"] == 0

    def test_update_modifies_only_specified_fields(self, db, knowledge):
        """update() changes only the fields passed, preserving others."""
        entry = knowledge.create(
            entry_type="gotcha",
            title="Original Title",
            content="Original content",
            domain="testing",
            tags="pytest",
        )
        original_created = db.execute_one(
            "SELECT created_at FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )["created_at"]

        knowledge.update(entry["id"], title="Updated Title", content="New content")

        row = db.execute_one(
            "SELECT * FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row["title"] == "Updated Title"
        assert row["content"] == "New content"
        assert row["domain"] == "testing"  # unchanged
        assert row["tags"] == "pytest"  # unchanged
        assert row["created_at"] == original_created  # unchanged
        assert row["updated_at"] is not None

    def test_confirm_sets_timestamp_and_clears_stale(self, db, knowledge):
        """confirm() sets last_confirmed_at and clears stale_flagged_at."""
        entry = knowledge.create(
            entry_type="expertise", title="Test", content="Test content",
        )
        # Manually set stale flag to verify confirm clears it
        db.execute(
            "UPDATE knowledge_entries SET stale_flagged_at = datetime('now') WHERE id = ?",
            (entry["id"],),
        )

        result = knowledge.confirm(entry["id"])
        assert result is True

        row = db.execute_one(
            "SELECT last_confirmed_at, stale_flagged_at FROM knowledge_entries WHERE id = ?",
            (entry["id"],),
        )
        assert row["last_confirmed_at"] is not None
        assert row["stale_flagged_at"] is None

    def test_confirm_nonexistent_returns_false(self, knowledge):
        """confirm() returns False for an ID that does not exist."""
        assert knowledge.confirm("kn-nonexistent") is False

    def test_record_application_increments_count(self, db, knowledge):
        """record_application() bumps applied_count and clears stale flag."""
        entry = knowledge.create(
            entry_type="expertise", title="Test", content="Test content",
        )
        db.execute(
            "UPDATE knowledge_entries SET stale_flagged_at = datetime('now') WHERE id = ?",
            (entry["id"],),
        )

        knowledge.record_application(entry["id"])
        knowledge.record_application(entry["id"])

        row = db.execute_one(
            "SELECT applied_count, stale_flagged_at FROM knowledge_entries WHERE id = ?",
            (entry["id"],),
        )
        assert row["applied_count"] == 2
        assert row["stale_flagged_at"] is None

    def test_prune_soft_deletes(self, db, knowledge):
        """prune() sets pruned_at but does not delete the row."""
        entry = knowledge.create(
            entry_type="gotcha", title="Stale", content="Remove me",
        )
        result = knowledge.prune(entry["id"])
        assert result is True

        row = db.execute_one(
            "SELECT pruned_at FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row["pruned_at"] is not None

        # Still exists in DB (soft delete)
        count = db.execute_one(
            "SELECT COUNT(*) as cnt FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert count["cnt"] == 1

    def test_prune_nonexistent_returns_false(self, knowledge):
        """prune() returns False for an ID that does not exist."""
        assert knowledge.prune("kn-nonexistent") is False

    def test_flag_stale_and_unflag(self, db, knowledge):
        """flag_stale() marks old entries; unflag_stale() clears the flag."""
        entry = knowledge.create(
            entry_type="expertise", title="Old Entry", content="Aged out",
        )
        # Backdate to make it eligible for staleness
        db.execute(
            """UPDATE knowledge_entries
               SET created_at = datetime('now', '-200 days'),
                   updated_at = datetime('now', '-200 days')
               WHERE id = ?""",
            (entry["id"],),
        )

        flagged = knowledge.flag_stale(stale_days=90)
        assert len(flagged) >= 1
        flagged_ids = [e["id"] for e in flagged]
        assert entry["id"] in flagged_ids

        row = db.execute_one(
            "SELECT stale_flagged_at FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row["stale_flagged_at"] is not None

        # Unflag
        result = knowledge.unflag_stale(entry["id"])
        assert result is True
        row = db.execute_one(
            "SELECT stale_flagged_at FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row["stale_flagged_at"] is None

    def test_auto_archive_stale_prunes_low_confidence_old_entries(self, db, knowledge):
        """auto_archive_stale() prunes entries past archive threshold with low confidence."""
        entry = knowledge.create(
            entry_type="observation", title="Fading", content="Low value",
        )
        # Backdate and lower confidence
        db.execute(
            """UPDATE knowledge_entries
               SET created_at = datetime('now', '-365 days'),
                   updated_at = datetime('now', '-365 days'),
                   confidence = 0.3
               WHERE id = ?""",
            (entry["id"],),
        )

        archived = knowledge.auto_archive_stale(archive_days=180, confidence_threshold=0.5)
        archived_ids = [e["id"] for e in archived]
        assert entry["id"] in archived_ids

        row = db.execute_one(
            "SELECT pruned_at FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert row["pruned_at"] is not None

    def test_auto_archive_skips_high_confidence(self, db, knowledge):
        """auto_archive_stale() does not prune high-confidence entries."""
        entry = knowledge.create(
            entry_type="expertise", title="High Value", content="Important",
        )
        db.execute(
            """UPDATE knowledge_entries
               SET created_at = datetime('now', '-365 days'),
                   updated_at = datetime('now', '-365 days'),
                   confidence = 0.9
               WHERE id = ?""",
            (entry["id"],),
        )

        archived = knowledge.auto_archive_stale(archive_days=180, confidence_threshold=0.5)
        archived_ids = [e["id"] for e in archived]
        assert entry["id"] not in archived_ids


# ---------------------------------------------------------------------------
# Pattern Write Lifecycle
# ---------------------------------------------------------------------------


class TestPatternWriteLifecycle:
    """Verify pattern mutation paths: create, evidence, confidence, delete."""

    def test_create_persists_all_fields(self, db, patterns):
        """Pattern create() stores all fields in the DB."""
        pat = patterns.create(
            type="process", domain="testing",
            title="TDD First", observation="Write tests before code",
        )
        row = db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],))
        assert row["type"] == "process"
        assert row["domain"] == "testing"
        assert row["title"] == "TDD First"
        assert row["observation"] == "Write tests before code"
        assert row["confidence"] == "low"
        assert row["confirmations"] == 0
        assert row["applications"] == 0

    def test_add_evidence_inserts_record_and_updates_pattern(self, db, patterns, sessions):
        """add_evidence() creates evidence row and bumps pattern applications."""
        pat = patterns.create(
            type="preference", domain="coding",
            title="Type hints", observation="Always use type hints",
        )
        session = sessions.start(project="test")
        patterns.add_evidence(pat["id"], session_id=session["id"])

        # Verify evidence row
        evidence = db.execute_one(
            "SELECT * FROM pattern_evidence WHERE pattern_id = ?", (pat["id"],)
        )
        assert evidence is not None
        assert evidence["session_id"] == session["id"]
        assert evidence["outcome"] == "confirmed"

        # Verify pattern updated
        row = db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],))
        assert row["applications"] == 1
        assert row["last_applied_at"] is not None

    def test_confidence_escalation_low_to_medium_to_high(self, db, patterns, sessions):
        """Confidence escalates: low → medium (3 confirmations) → high (8)."""
        pat = patterns.create(
            type="process", domain="arch",
            title="Escalation Test", observation="Testing confidence levels",
        )
        assert pat["confidence"] == "low"

        # 3 confirmations → medium
        for _ in range(3):
            s = sessions.start(project="test")
            patterns.add_evidence(pat["id"], session_id=s["id"])
            sessions.end(s["id"])

        row = db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],))
        assert row["confidence"] == "medium"
        assert row["confirmations"] == 3

        # 5 more (total 8) → high
        for _ in range(5):
            s = sessions.start(project="test")
            patterns.add_evidence(pat["id"], session_id=s["id"])
            sessions.end(s["id"])

        row = db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],))
        assert row["confidence"] == "high"
        assert row["confirmations"] == 8

    def test_delete_removes_pattern_and_evidence(self, db, patterns, sessions):
        """delete() removes both the pattern row and all evidence rows."""
        pat = patterns.create(
            type="process", domain="cleanup",
            title="Delete Target", observation="This will be deleted",
        )
        s = sessions.start(project="test")
        patterns.add_evidence(pat["id"], session_id=s["id"])

        result = patterns.delete(pat["id"])
        assert result is True

        assert db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],)) is None
        evidence = db.execute_one(
            "SELECT * FROM pattern_evidence WHERE pattern_id = ?", (pat["id"],)
        )
        assert evidence is None

    def test_delete_nonexistent_returns_false(self, patterns):
        """delete() returns False for a pattern that does not exist."""
        assert patterns.delete("pat-nonexistent") is False

    def test_evidence_with_work_item_id(self, db, patterns, sessions, work_items):
        """Evidence can reference a work item for traceability."""
        pat = patterns.create(
            type="process", domain="tracking",
            title="Work Tracking", observation="Track evidence to work items",
        )
        s = sessions.start(project="test")
        w = work_items.create(title="Feature X")
        patterns.add_evidence(pat["id"], session_id=s["id"], work_item_id=w["id"])

        evidence = db.execute_one(
            "SELECT * FROM pattern_evidence WHERE pattern_id = ?", (pat["id"],)
        )
        assert evidence["work_item_id"] == w["id"]


# ---------------------------------------------------------------------------
# Session Write Lifecycle
# ---------------------------------------------------------------------------


class TestSessionWriteLifecycle:
    """Verify session creation, state updates, checkpoints, and ending."""

    def test_start_persists_session(self, db, sessions):
        """start() creates a session row with correct initial state."""
        s = sessions.start(project="greymatter")
        row = db.execute_one("SELECT * FROM sessions WHERE id = ?", (s["id"],))
        assert row["project"] == "greymatter"
        assert row["ended_at"] is None
        assert row["state"] == "active"
        assert row["compaction_count"] == 0

    def test_end_sets_timestamp_and_summary(self, db, sessions):
        """end() populates ended_at and summary."""
        s = sessions.start(project="test")
        sessions.end(s["id"], summary="Completed integration tests")

        row = db.execute_one("SELECT * FROM sessions WHERE id = ?", (s["id"],))
        assert row["ended_at"] is not None
        assert row["summary"] == "Completed integration tests"

    def test_checkpoint_creates_checkpoint_row(self, db, sessions):
        """checkpoint() inserts a session_checkpoints row and updates session."""
        s = sessions.start(project="test")
        cp = sessions.checkpoint(
            s["id"],
            context_summary="Working on auth module",
            open_items="Fix token validation",
        )
        assert "checkpoint_id" in cp

        cp_row = db.execute_one(
            "SELECT * FROM session_checkpoints WHERE id = ?", (cp["checkpoint_id"],)
        )
        assert cp_row is not None
        assert cp_row["session_id"] == s["id"]
        assert cp_row["context_summary"] == "Working on auth module"
        assert cp_row["open_items"] == "Fix token validation"

        # Verify session checkpoint_at updated
        s_row = db.execute_one("SELECT checkpoint_at FROM sessions WHERE id = ?", (s["id"],))
        assert s_row["checkpoint_at"] is not None

    def test_update_state_changes_state_field(self, db, sessions):
        """update_state() changes the session state field."""
        s = sessions.start(project="test")
        sessions.update_state(s["id"], "paused")

        row = db.execute_one("SELECT state FROM sessions WHERE id = ?", (s["id"],))
        assert row["state"] == "paused"

    def test_update_state_with_active_work_item(self, db, sessions, work_items):
        """update_state() can set active_work_item_id."""
        s = sessions.start(project="test")
        w = work_items.create(title="Current Work")
        sessions.update_state(s["id"], "working", active_work_item_id=w["id"])

        row = db.execute_one(
            "SELECT state, active_work_item_id FROM sessions WHERE id = ?", (s["id"],)
        )
        assert row["state"] == "working"
        assert row["active_work_item_id"] == w["id"]

    def test_increment_compaction_bumps_counter(self, db, sessions):
        """increment_compaction() increments the compaction_count."""
        s = sessions.start(project="test")
        count1 = sessions.increment_compaction(s["id"])
        count2 = sessions.increment_compaction(s["id"])

        assert count1 == 1
        assert count2 == 2

        row = db.execute_one(
            "SELECT compaction_count FROM sessions WHERE id = ?", (s["id"],)
        )
        assert row["compaction_count"] == 2

    def test_multiple_checkpoints_accumulate(self, db, sessions):
        """Multiple checkpoints for one session all persist."""
        s = sessions.start(project="test")
        cp1 = sessions.checkpoint(s["id"], context_summary="Checkpoint 1")
        cp2 = sessions.checkpoint(s["id"], context_summary="Checkpoint 2")
        cp3 = sessions.checkpoint(s["id"], context_summary="Checkpoint 3")

        rows = db.execute(
            "SELECT * FROM session_checkpoints WHERE session_id = ? ORDER BY checkpoint_at",
            (s["id"],),
        )
        assert len(rows) == 3


# ---------------------------------------------------------------------------
# Work Item Write Lifecycle
# ---------------------------------------------------------------------------


class TestWorkItemWriteLifecycle:
    """Verify work item creation, status transitions, and deletion."""

    def test_create_persists_all_fields(self, db, work_items):
        """create() stores all fields including computed short_id."""
        w = work_items.create(
            title="Build auth",
            description="Implement JWT authentication",
            priority=10,
            domain_tags="security,auth",
            project="greymatter",
            feature="auth",
        )
        row = db.execute_one("SELECT * FROM work_items WHERE id = ?", (w["id"],))
        assert row["title"] == "Build auth"
        assert row["description"] == "Implement JWT authentication"
        assert row["priority"] == 10
        assert row["domain_tags"] == "security,auth"
        assert row["project"] == "greymatter"
        assert row["feature"] == "auth"
        assert row["status"] == "queued"
        assert row["short_id"] is not None

    def test_status_transition_chain(self, db, work_items):
        """Work item goes through full status lifecycle."""
        w = work_items.create(title="Feature Y")

        work_items.update_status(w["id"], "in_progress")
        row = db.execute_one("SELECT status FROM work_items WHERE id = ?", (w["id"],))
        assert row["status"] == "in_progress"

        work_items.update_status(w["id"], "pending_review")
        row = db.execute_one("SELECT status FROM work_items WHERE id = ?", (w["id"],))
        assert row["status"] == "pending_review"

        work_items.update_review(w["id"], "needs_revision", review_notes="Add more tests")
        row = db.execute_one(
            "SELECT status, review_notes FROM work_items WHERE id = ?", (w["id"],)
        )
        assert row["status"] == "needs_revision"
        assert row["review_notes"] == "Add more tests"

    def test_complete_sets_timestamp(self, db, work_items):
        """complete() sets completed_at and status."""
        w = work_items.create(title="Task Z")
        work_items.complete(w["id"])

        row = db.execute_one(
            "SELECT status, completed_at FROM work_items WHERE id = ?", (w["id"],)
        )
        assert row["status"] == "completed"
        assert row["completed_at"] is not None

    def test_delete_removes_row(self, db, work_items):
        """delete() physically removes the work item."""
        w = work_items.create(title="Delete Me")
        result = work_items.delete(w["id"])
        assert result is True

        row = db.execute_one("SELECT * FROM work_items WHERE id = ?", (w["id"],))
        assert row is None

    def test_delete_nonexistent_returns_false(self, work_items):
        """delete() returns False for an ID that does not exist."""
        assert work_items.delete("wi-nonexistent") is False


# ---------------------------------------------------------------------------
# Document Write Lifecycle
# ---------------------------------------------------------------------------


class TestDocumentWriteLifecycle:
    """Verify document store creation, summarization, and token estimation."""

    def test_create_persists_with_token_estimate(self, db, doc_store):
        """create() stores document with computed token_estimate."""
        doc = doc_store.create(
            doc_type="design",
            title="Architecture Doc",
            content="This is a design document with substantial content " * 10,
            tags="architecture",
            project="greymatter",
        )
        row = db.execute_one("SELECT * FROM documents WHERE id = ?", (doc["id"],))
        assert row["doc_type"] == "design"
        assert row["title"] == "Architecture Doc"
        assert row["tags"] == "architecture"
        assert row["project"] == "greymatter"
        assert row["token_estimate"] > 0

    def test_summarize_updates_summary(self, db, doc_store):
        """summarize() attaches summary to existing document."""
        doc = doc_store.create(
            doc_type="research",
            title="Research Notes",
            content="Detailed research findings about vector databases",
        )
        doc_store.summarize(doc["id"], "Key findings about pgvector vs sqlite-vec")

        row = db.execute_one(
            "SELECT summary, updated_at FROM documents WHERE id = ?", (doc["id"],)
        )
        assert row["summary"] == "Key findings about pgvector vs sqlite-vec"
        assert row["updated_at"] is not None

    def test_parent_child_relationship(self, db, doc_store):
        """Documents can reference a parent document."""
        parent = doc_store.create(
            doc_type="design", title="Parent Doc", content="Top-level design",
        )
        child = doc_store.create(
            doc_type="design", title="Sub-section",
            content="Detail of parent", parent_id=parent["id"],
        )
        row = db.execute_one("SELECT parent_id FROM documents WHERE id = ?", (child["id"],))
        assert row["parent_id"] == parent["id"]


# ---------------------------------------------------------------------------
# Quality Engine Merge Writes
# ---------------------------------------------------------------------------


class TestQualityMergeWrites:
    """Verify merge_duplicates write correctness."""

    def test_merge_duplicates_combines_content(self, db, knowledge, quality):
        """merge_duplicates() appends remove content to keep and prunes remove."""
        keep = knowledge.create(
            entry_type="expertise", title="SQLite WAL",
            content="WAL enables concurrent reads",
        )
        remove = knowledge.create(
            entry_type="expertise", title="SQLite WAL Mode",
            content="WAL also improves write throughput",
        )
        result = quality.merge_duplicates(keep["id"], remove["id"])
        assert result is True

        keep_row = db.execute_one(
            "SELECT content FROM knowledge_entries WHERE id = ?", (keep["id"],)
        )
        assert "concurrent reads" in keep_row["content"]
        assert "write throughput" in keep_row["content"]

        remove_row = db.execute_one(
            "SELECT pruned_at FROM knowledge_entries WHERE id = ?", (remove["id"],)
        )
        assert remove_row["pruned_at"] is not None

    def test_merge_nonexistent_returns_false(self, quality):
        """merge_duplicates() returns False when either ID is missing."""
        assert quality.merge_duplicates("kn-fake1", "kn-fake2") is False


# ---------------------------------------------------------------------------
# Soul File Write Lifecycle
# ---------------------------------------------------------------------------


class TestSoulWriteLifecycle:
    """Verify soul document file-based mutations."""

    def test_create_initial_soul_creates_file(self, soul):
        """create_initial_soul() creates the soul file on disk."""
        assert not soul.exists()
        soul.create_initial_soul("Keith")
        assert soul.exists()

        content = soul.load()
        assert "Keith" in content
        assert "## Identity" in content

    def test_add_learned_preference_persists(self, soul):
        """add_learned_preference() appends and persists to file."""
        soul.create_initial_soul("Keith")
        soul.add_learned_preference("Uses pytest over unittest")

        content = soul.load()
        assert "Uses pytest over unittest" in content

    def test_multiple_preferences_accumulate(self, soul):
        """Multiple preferences all persist in the file."""
        soul.create_initial_soul("Keith")
        prefs = ["TDD workflow", "Type hints always", "No print() in production"]
        for pref in prefs:
            soul.add_learned_preference(pref)

        content = soul.load()
        for pref in prefs:
            assert pref in content

    def test_session_count_increments_correctly(self, soul):
        """increment_session_count() produces sequential counts."""
        soul.create_initial_soul("Keith")
        c1 = soul.increment_session_count()
        c2 = soul.increment_session_count()
        c3 = soul.increment_session_count()
        assert c2 == c1 + 1
        assert c3 == c2 + 1

    def test_relationship_moment_persists(self, soul):
        """add_relationship_moment() writes to file."""
        soul.create_initial_soul("Keith")
        soul.add_relationship_moment("First successful deployment together")

        content = soul.load()
        assert "First successful deployment together" in content


# ---------------------------------------------------------------------------
# Cross-Module Write Consistency
# ---------------------------------------------------------------------------


class TestCrossModuleWriteConsistency:
    """Verify writes that span multiple tables maintain consistency."""

    def test_pattern_evidence_links_session_and_work_item(
        self, db, patterns, sessions, work_items
    ):
        """Evidence write correctly references both session and work item."""
        s = sessions.start(project="test")
        w = work_items.create(title="Feature")
        pat = patterns.create(
            type="process", domain="test",
            title="Cross-ref", observation="Cross-reference test",
        )
        patterns.add_evidence(pat["id"], session_id=s["id"], work_item_id=w["id"])

        # Verify all three entities exist and are linked
        evidence = db.execute_one(
            "SELECT * FROM pattern_evidence WHERE pattern_id = ?", (pat["id"],)
        )
        assert evidence["session_id"] == s["id"]
        assert evidence["work_item_id"] == w["id"]

        # Verify session and work item still valid
        assert db.execute_one("SELECT id FROM sessions WHERE id = ?", (s["id"],)) is not None
        assert db.execute_one("SELECT id FROM work_items WHERE id = ?", (w["id"],)) is not None

    def test_session_work_item_knowledge_pipeline(
        self, db, knowledge, sessions, work_items
    ):
        """Full pipeline: session → work item → knowledge creation stays consistent."""
        s = sessions.start(project="greymatter")
        w = work_items.create(title="Build knowledge pipeline", project="greymatter")
        sessions.update_state(s["id"], "working", active_work_item_id=w["id"])

        entry = knowledge.create(
            entry_type="expertise",
            title="Pipeline Pattern",
            content="Knowledge created during work item execution",
            domain="orchestration",
        )

        work_items.complete(w["id"])
        sessions.end(s["id"], summary="Built knowledge pipeline")

        # Verify final state
        s_row = db.execute_one("SELECT * FROM sessions WHERE id = ?", (s["id"],))
        assert s_row["ended_at"] is not None
        assert s_row["summary"] == "Built knowledge pipeline"

        w_row = db.execute_one("SELECT * FROM work_items WHERE id = ?", (w["id"],))
        assert w_row["status"] == "completed"
        assert w_row["completed_at"] is not None

        k_row = db.execute_one(
            "SELECT * FROM knowledge_entries WHERE id = ?", (entry["id"],)
        )
        assert k_row is not None

    def test_knowledge_prune_does_not_affect_patterns(self, db, knowledge, patterns):
        """Pruning a knowledge entry does not cascade to pattern data."""
        entry = knowledge.create(
            entry_type="gotcha", title="Prunable",
            content="This will be pruned", domain="test",
        )
        pat = patterns.create(
            type="process", domain="test",
            title="Surviving Pattern", observation="Should survive pruning",
        )

        knowledge.prune(entry["id"])

        # Pattern unaffected
        pat_row = db.execute_one("SELECT * FROM patterns WHERE id = ?", (pat["id"],))
        assert pat_row is not None
        assert pat_row["title"] == "Surviving Pattern"

    def test_quality_merge_preserves_other_entries(self, db, knowledge, quality):
        """merge_duplicates affects only the two specified entries."""
        keep = knowledge.create(
            entry_type="expertise", title="Keep", content="Keep this",
        )
        remove = knowledge.create(
            entry_type="expertise", title="Remove", content="Remove this",
        )
        bystander = knowledge.create(
            entry_type="expertise", title="Bystander", content="Should not change",
        )

        quality.merge_duplicates(keep["id"], remove["id"])

        bystander_row = db.execute_one(
            "SELECT content, pruned_at FROM knowledge_entries WHERE id = ?",
            (bystander["id"],),
        )
        assert bystander_row["content"] == "Should not change"
        assert bystander_row["pruned_at"] is None


# ---------------------------------------------------------------------------
# Write Idempotency
# ---------------------------------------------------------------------------


class TestWriteIdempotency:
    """Verify operations that should be idempotent behave correctly."""

    def test_double_prune_is_safe(self, knowledge):
        """Pruning the same entry twice does not error."""
        entry = knowledge.create(
            entry_type="gotcha", title="Double Prune", content="Test",
        )
        assert knowledge.prune(entry["id"]) is True
        # Second prune — should not raise
        result = knowledge.prune(entry["id"])
        # May return True or False depending on implementation, but must not raise
        assert isinstance(result, bool)

    def test_double_confirm_is_safe(self, knowledge):
        """Confirming the same entry twice updates timestamp each time."""
        entry = knowledge.create(
            entry_type="expertise", title="Double Confirm", content="Test",
        )
        assert knowledge.confirm(entry["id"]) is True
        assert knowledge.confirm(entry["id"]) is True

    def test_double_complete_is_safe(self, work_items):
        """Completing a work item twice does not raise."""
        w = work_items.create(title="Double Complete")
        work_items.complete(w["id"])
        result = work_items.complete(w["id"])
        # Should not raise; result may vary
        assert result is not None or result is None

    def test_multiple_evidence_same_session(self, db, patterns, sessions):
        """Multiple evidence records from same session accumulate correctly."""
        pat = patterns.create(
            type="process", domain="test",
            title="Multi Evidence", observation="Test",
        )
        s = sessions.start(project="test")
        patterns.add_evidence(pat["id"], session_id=s["id"])
        patterns.add_evidence(pat["id"], session_id=s["id"])

        row = db.execute_one("SELECT applications FROM patterns WHERE id = ?", (pat["id"],))
        assert row["applications"] == 2

        evidence_count = db.execute_one(
            "SELECT COUNT(*) as cnt FROM pattern_evidence WHERE pattern_id = ?",
            (pat["id"],),
        )
        assert evidence_count["cnt"] == 2


# ---------------------------------------------------------------------------
# Write Error Handling
# ---------------------------------------------------------------------------


class TestWriteErrorHandling:
    """Verify that invalid writes fail gracefully."""

    def test_knowledge_update_nonexistent(self, knowledge):
        """update() on a nonexistent ID returns None."""
        result = knowledge.update("kn-nonexistent", title="Ghost")
        assert result is None

    def test_work_item_update_status_nonexistent(self, work_items):
        """update_status() on a nonexistent ID returns None."""
        result = work_items.update_status("wi-nonexistent", "in_progress")
        assert result is None

    def test_session_end_nonexistent(self, sessions):
        """end() on a nonexistent session returns None."""
        result = sessions.end("sess-nonexistent", summary="Ghost session")
        assert result is None

    def test_document_summarize_nonexistent_does_not_raise(self, doc_store):
        """summarize() on a nonexistent doc does not raise (no-op)."""
        # Should not raise — the UPDATE just matches 0 rows
        doc_store.summarize("doc-nonexistent", "Ghost summary")
