"""Tests for full sync."""
import pytest

from greymatter_core.db import SQLiteDatabase
from greymatter_core.schema.migrations import apply_all
from greymatter_core.sync.full import full_sync, _upsert_row
from greymatter_core.sync.tracking import (
    get_sync_version,
    install_sqlite_triggers,
)


def _make_db():
    """Create a fresh DB with schema + migration + triggers."""
    d = SQLiteDatabase(":memory:")
    apply_all(d)
    install_sqlite_triggers(d)
    return d


@pytest.fixture
def source():
    return _make_db()


@pytest.fixture
def target():
    return _make_db()


class TestFullSync:
    def test_empty_source_syncs_zero_rows(self, source, target):
        result = full_sync(source, target)
        assert result.success
        assert result.rows_pushed == 0
        assert result.tables_synced == 0

    def test_syncs_patterns(self, source, target):
        source.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "Test", "Obs"),
        )
        result = full_sync(source, target)
        assert result.success
        assert result.rows_pushed >= 1

        row = target.execute_one("SELECT * FROM patterns WHERE id = ?", ("p-1",))
        assert row is not None
        assert row["title"] == "Test"

    def test_syncs_multiple_tables(self, source, target):
        source.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "P1", "O1"),
        )
        source.execute(
            "INSERT INTO observations (id, session_id, trigger, category, title, content) "
            "VALUES (?, ?, ?, ?, ?, ?)",
            ("obs-1", "s-1", "manual", "insight", "Test", "Content"),
        )
        result = full_sync(source, target)
        assert result.success
        assert result.tables_synced >= 2
        assert result.rows_pushed >= 2

    def test_upsert_updates_existing_row(self, source, target):
        # Insert into target first
        target.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "Old Title", "Old Obs"),
        )
        # Source has updated version
        source.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "New Title", "New Obs"),
        )
        result = full_sync(source, target)
        assert result.success

        row = target.execute_one("SELECT * FROM patterns WHERE id = ?", ("p-1",))
        assert row["title"] == "New Title"

    def test_copies_sync_version(self, source, target):
        source.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "P1", "O1"),
        )
        # Source sync_version should be 1 after insert trigger
        full_sync(source, target)
        assert get_sync_version(target) == get_sync_version(source)

    def test_selective_table_sync(self, source, target):
        source.execute(
            "INSERT INTO patterns (id, type, domain, title, observation) "
            "VALUES (?, ?, ?, ?, ?)",
            ("p-1", "process", "testing", "P1", "O1"),
        )
        source.execute(
            "INSERT INTO observations (id, session_id, trigger, category, title, content) "
            "VALUES (?, ?, ?, ?, ?, ?)",
            ("obs-1", "s-1", "manual", "insight", "Test", "Content"),
        )
        # Only sync patterns
        result = full_sync(source, target, tables=["patterns"])
        assert result.tables_synced == 1

        # Patterns should exist, observations should not
        assert target.execute_one("SELECT * FROM patterns WHERE id = ?", ("p-1",)) is not None
        assert target.execute_one("SELECT * FROM observations WHERE id = ?", ("obs-1",)) is None

    def test_sync_result_reports_errors(self, source, target):
        # Sync a table that doesn't exist in target
        result = full_sync(source, target, tables=["nonexistent_table"])
        assert not result.success
        assert len(result.errors) >= 1

    def test_large_batch_sync(self, source, target):
        # Insert many rows to test batching
        for i in range(25):
            source.execute(
                "INSERT INTO patterns (id, type, domain, title, observation) "
                "VALUES (?, ?, ?, ?, ?)",
                (f"p-{i}", "process", "testing", f"P{i}", f"O{i}"),
            )
        result = full_sync(source, target, batch_size=10)
        assert result.success
        assert result.rows_pushed == 25

        rows = target.execute("SELECT * FROM patterns")
        assert len(rows) == 25
