"""Tests for the unified schema module."""
import sqlite3

import pytest

from greymatter_core.schema import (
    get_full_crdb_schema,
    get_full_sqlite_schema,
    get_module_names,
    SCHEMA_VERSION,
)
from greymatter_core.schema import core, cognitive, distributed, salesos, twin


class TestSchemaRegistry:
    """Tests for the schema registry (__init__.py)."""

    def test_schema_version_is_set(self):
        assert SCHEMA_VERSION == "1.0"

    def test_module_names_returns_all_groups(self):
        names = get_module_names()
        assert "core" in names
        assert "cognitive" in names
        assert "distributed" in names
        assert "salesos" in names
        assert "twin" in names

    def test_full_sqlite_schema_not_empty(self):
        ddl = get_full_sqlite_schema()
        assert len(ddl) > 1000
        assert "CREATE TABLE" in ddl

    def test_full_crdb_schema_not_empty(self):
        ddl = get_full_crdb_schema()
        assert len(ddl) > 1000
        assert "CREATE TABLE" in ddl

    def test_sqlite_schema_has_no_crdb_syntax(self):
        ddl = get_full_sqlite_schema()
        assert "gen_random_uuid()" not in ddl
        assert "TIMESTAMPTZ" not in ddl
        assert "JSONB" not in ddl

    def test_crdb_schema_has_no_sqlite_syntax(self):
        ddl = get_full_crdb_schema()
        assert "AUTOINCREMENT" not in ddl
        assert "datetime('now')" not in ddl


class TestCoreSchemaSQLite:
    """Tests for core schema module with SQLite."""

    def test_sqlite_ddl_creates_tables(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(core.get_sqlite_ddl())
        tables = [
            row[0] for row in
            conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
        ]
        assert "patterns" in tables
        assert "knowledge_entries" in tables
        assert "work_items" in tables
        assert "sessions" in tables
        assert "documents" in tables
        assert "corrections" in tables
        assert "soul_index" in tables
        assert "_schema_metadata" in tables
        conn.close()

    def test_core_tables_accept_inserts(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(core.get_sqlite_ddl())
        conn.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES ('p-1', 'correction', 'python', 'Test', 'Always run tests')"
        )
        conn.execute(
            "INSERT INTO work_items (id, title) VALUES ('wi-1', 'Test task')"
        )
        row = conn.execute("SELECT * FROM patterns WHERE id = 'p-1'").fetchone()
        assert row is not None
        conn.close()


class TestCognitiveSchemaSQLite:
    """Tests for cognitive schema module with SQLite."""

    def test_observations_table_created(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(cognitive.get_sqlite_ddl())
        tables = [
            row[0] for row in
            conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
        ]
        assert "observations" in tables
        assert "observation_sessions" in tables
        assert "knowledge" in tables
        conn.close()

    def test_observation_insert_with_defaults(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(cognitive.get_sqlite_ddl())
        conn.execute(
            "INSERT INTO observations (id, session_id, trigger, category, title, content) "
            "VALUES ('obs-1', 'sess-1', 'hook', 'insight', 'Test', 'Test content')"
        )
        row = conn.execute("SELECT confidence, stability_days, pruned FROM observations WHERE id = 'obs-1'").fetchone()
        assert row[0] == 0.5  # default confidence
        assert row[1] == 45   # default stability
        assert row[2] == 0    # not pruned
        conn.close()


class TestDistributedSchemaSQLite:
    """Tests for distributed schema module with SQLite."""

    def test_agents_table_created(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(distributed.get_sqlite_ddl())
        tables = [
            row[0] for row in
            conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
        ]
        assert "agents" in tables
        assert "worker_nodes" in tables
        assert "worktrees" in tables
        assert "work_queue" in tables
        assert "api_keys" in tables
        conn.close()


class TestSalesosSchemaSQLite:
    """Tests for SalesOS schema module with SQLite."""

    def test_salesos_tables_created(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(salesos.get_sqlite_ddl())
        tables = [
            row[0] for row in
            conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
        ]
        assert "deal_forecasts" in tables
        assert "proposals" in tables
        assert "slack_channels" in tables
        assert "token_usage" in tables
        assert "salesos_accounts" in tables
        conn.close()


class TestTwinSchemaSQLite:
    """Tests for Digital Twin schema module with SQLite."""

    def test_twin_tables_created(self):
        conn = sqlite3.connect(":memory:")
        conn.executescript(twin.get_sqlite_ddl())
        tables = [
            row[0] for row in
            conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
        ]
        assert "twin_profiles" in tables
        assert "twin_values" in tables
        assert "twin_energy_readings" in tables
        assert "twin_growth_entries" in tables
        assert "twin_interventions" in tables
        assert "twin_energy_patterns" in tables
        conn.close()


class TestCRDBDDLSyntax:
    """Verify CockroachDB DDL strings contain expected patterns."""

    def test_core_crdb_uses_uuid_pks(self):
        ddl = core.get_crdb_ddl()
        assert "UUID PRIMARY KEY DEFAULT gen_random_uuid()" in ddl

    def test_core_crdb_uses_timestamptz(self):
        ddl = core.get_crdb_ddl()
        assert "TIMESTAMPTZ DEFAULT now()" in ddl

    def test_cognitive_crdb_has_observation_indexes(self):
        ddl = cognitive.get_crdb_ddl()
        assert "idx_observations_session" in ddl
        assert "idx_observations_category" in ddl
        assert "idx_observations_confidence" in ddl

    def test_salesos_crdb_uses_jsonb(self):
        ddl = salesos.get_crdb_ddl()
        assert "JSONB" in ddl

    def test_distributed_crdb_has_cascade_deletes(self):
        ddl = distributed.get_crdb_ddl()
        assert "ON DELETE CASCADE" in ddl


class TestSchemaNoTableDuplicates:
    """Ensure no table name is defined in multiple modules."""

    def _extract_table_names(self, ddl: str) -> set[str]:
        import re
        return set(re.findall(r"CREATE TABLE IF NOT EXISTS (\w+)", ddl))

    def test_no_duplicate_tables_sqlite(self):
        all_tables: dict[str, str] = {}
        for name, module in [
            ("core", core), ("cognitive", cognitive),
            ("distributed", distributed), ("salesos", salesos), ("twin", twin),
        ]:
            tables = self._extract_table_names(module.get_sqlite_ddl())
            for t in tables:
                if t in all_tables:
                    pytest.fail(
                        f"Table '{t}' defined in both '{all_tables[t]}' and '{name}'"
                    )
                all_tables[t] = name

    def test_no_duplicate_tables_crdb(self):
        all_tables: dict[str, str] = {}
        for name, module in [
            ("core", core), ("cognitive", cognitive),
            ("distributed", distributed), ("salesos", salesos), ("twin", twin),
        ]:
            tables = self._extract_table_names(module.get_crdb_ddl())
            for t in tables:
                if t in all_tables:
                    pytest.fail(
                        f"Table '{t}' defined in both '{all_tables[t]}' and '{name}'"
                    )
                all_tables[t] = name
