"""Extended schema tests — verifies column constraints, defaults, indexes, and DDL for all core tables."""
import pytest

from greymatter_core.db import SQLiteDatabase
from greymatter_core.schema.core import get_sqlite_ddl, get_crdb_ddl


@pytest.fixture
def db():
    return SQLiteDatabase(":memory:")


# --- Column defaults ---

class TestColumnDefaults:
    def test_pattern_defaults(self, db):
        db.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "Title", "Observation"),
        )
        row = db.execute_one("SELECT * FROM patterns WHERE id = 'p-1'")
        assert row["confidence"] == "low"
        assert row["confirmations"] == 0
        assert row["applications"] == 0
        assert row["last_applied_at"] is None
        assert row["created_at"] is not None

    def test_knowledge_defaults(self, db):
        db.execute(
            "INSERT INTO knowledge_entries (id, entry_type, title, content) VALUES (?, ?, ?, ?)",
            ("k-1", "reference", "Title", "Content"),
        )
        row = db.execute_one("SELECT * FROM knowledge_entries WHERE id = 'k-1'")
        assert row["scope"] == "cross-cutting"
        assert row["confidence"] == 0.5
        assert row["applied_count"] == 0
        assert row["domain"] is None
        assert row["tags"] is None
        assert row["pruned_at"] is None

    def test_work_item_defaults(self, db):
        db.execute(
            "INSERT INTO work_items (id, title) VALUES (?, ?)",
            ("wi-1", "Fix bug"),
        )
        row = db.execute_one("SELECT * FROM work_items WHERE id = 'wi-1'")
        assert row["status"] == "queued"
        assert row["priority"] == 100
        assert row["project"] == "greymatter"
        assert row["feature"] == "general"
        assert row["type"] == "task"
        assert row["completed_at"] is None

    def test_session_defaults(self, db):
        db.execute("INSERT INTO sessions (id) VALUES (?)", ("s-1",))
        row = db.execute_one("SELECT * FROM sessions WHERE id = 's-1'")
        assert row["state"] == "active"
        assert row["compaction_count"] == 0
        assert row["started_at"] is not None

    def test_llm_completion_defaults(self, db):
        db.execute(
            "INSERT INTO llm_completions (provider, model) VALUES (?, ?)",
            ("anthropic", "opus-4"),
        )
        row = db.execute_one("SELECT * FROM llm_completions WHERE provider = 'anthropic'")
        assert row["cost_estimate"] == 0.0
        assert row["timestamp"] is not None

    def test_document_defaults(self, db):
        db.execute(
            "INSERT INTO documents (id, doc_type, title, content) VALUES (?, ?, ?, ?)",
            ("d-1", "design", "Doc", "Content"),
        )
        row = db.execute_one("SELECT * FROM documents WHERE id = 'd-1'")
        assert row["format"] == "markdown"
        assert row["tags"] is None
        assert row["project"] is None


# --- NOT NULL constraints ---

class TestNotNullConstraints:
    def test_pattern_requires_type(self, db):
        with pytest.raises(Exception):
            db.execute(
                "INSERT INTO patterns (id, domain, title, observation) VALUES (?, ?, ?, ?)",
                ("p-1", "testing", "Title", "Obs"),
            )

    def test_pattern_requires_domain(self, db):
        with pytest.raises(Exception):
            db.execute(
                "INSERT INTO patterns (id, type, title, observation) VALUES (?, ?, ?, ?)",
                ("p-1", "process", "Title", "Obs"),
            )

    def test_knowledge_requires_entry_type(self, db):
        with pytest.raises(Exception):
            db.execute(
                "INSERT INTO knowledge_entries (id, title, content) VALUES (?, ?, ?)",
                ("k-1", "Title", "Content"),
            )

    def test_work_item_requires_title(self, db):
        with pytest.raises(Exception):
            db.execute("INSERT INTO work_items (id) VALUES (?)", ("wi-1",))

    def test_correction_requires_fields(self, db):
        with pytest.raises(Exception):
            db.execute(
                "INSERT INTO corrections (id, domain) VALUES (?, ?)",
                ("c-1", "testing"),
            )


# --- Foreign key relationships ---

class TestForeignKeys:
    def test_pattern_evidence_references_pattern(self, db):
        db.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "Title", "Obs"),
        )
        db.execute(
            "INSERT INTO pattern_evidence (pattern_id, outcome) VALUES (?, ?)",
            ("p-1", "confirmed"),
        )
        rows = db.execute("SELECT * FROM pattern_evidence WHERE pattern_id = 'p-1'")
        assert len(rows) == 1
        assert rows[0]["outcome"] == "confirmed"

    def test_session_checkpoint_references_session(self, db):
        db.execute("INSERT INTO sessions (id) VALUES (?)", ("s-1",))
        db.execute(
            "INSERT INTO session_checkpoints (id, session_id, checkpoint_at, state) VALUES (?, ?, ?, ?)",
            ("cp-1", "s-1", "2026-03-09T00:00:00", "active"),
        )
        row = db.execute_one("SELECT * FROM session_checkpoints WHERE id = 'cp-1'")
        assert row["session_id"] == "s-1"


# --- DDL functions ---

class TestDDLFunctions:
    def test_sqlite_ddl_returns_string(self):
        ddl = get_sqlite_ddl()
        assert isinstance(ddl, str)
        assert "CREATE TABLE" in ddl

    def test_crdb_ddl_returns_string(self):
        ddl = get_crdb_ddl()
        assert isinstance(ddl, str)
        assert "CREATE TABLE" in ddl

    def test_sqlite_ddl_has_all_tables(self):
        ddl = get_sqlite_ddl()
        for table in ["patterns", "knowledge_entries", "work_items", "sessions",
                       "documents", "corrections", "soul_index", "drift_warnings"]:
            assert table in ddl, f"Missing table: {table}"

    def test_crdb_ddl_uses_uuid_primary_keys(self):
        ddl = get_crdb_ddl()
        assert "UUID PRIMARY KEY" in ddl
        assert "gen_random_uuid()" in ddl

    def test_crdb_ddl_uses_timestamptz(self):
        ddl = get_crdb_ddl()
        assert "TIMESTAMPTZ" in ddl


# --- Multi-row operations ---

class TestMultiRowOperations:
    def test_bulk_pattern_insert_and_count(self, db):
        for i in range(25):
            db.execute(
                "INSERT INTO patterns (id, type, domain, title, observation) VALUES (?, ?, ?, ?, ?)",
                (f"p-{i}", "process", "testing", f"Pattern {i}", f"Observation {i}"),
            )
        rows = db.execute("SELECT COUNT(*) as c FROM patterns")
        assert rows[0]["c"] == 25

    def test_work_item_status_filter(self, db):
        for i, status in enumerate(["queued", "in_progress", "completed", "failed", "queued"]):
            db.execute(
                "INSERT INTO work_items (id, title, status) VALUES (?, ?, ?)",
                (f"wi-{i}", f"Item {i}", status),
            )
        active = db.execute("SELECT * FROM work_items WHERE status = 'in_progress'")
        assert len(active) == 1
        queued = db.execute("SELECT * FROM work_items WHERE status = 'queued'")
        assert len(queued) == 2

    def test_knowledge_entries_with_tags(self, db):
        db.execute(
            "INSERT INTO knowledge_entries (id, entry_type, title, content, tags) VALUES (?, ?, ?, ?, ?)",
            ("k-1", "reference", "API Design", "REST patterns", "api,design,rest"),
        )
        row = db.execute_one("SELECT tags FROM knowledge_entries WHERE id = 'k-1'")
        assert "api" in row["tags"]
        assert "design" in row["tags"]
