"""Tests for belief change history (#1280)."""
from __future__ import annotations

import sqlite3
import pytest

from cortex.core.belief_history import (
    BeliefChange,
    BeliefHistory,
    get_belief_history,
    get_belief_changes_for_entity,
)


class _FakeStorage:
    """Minimal storage mock with a real SQLite DB for belief history queries."""

    def __init__(self):
        self.conn = sqlite3.connect(":memory:")
        self.conn.execute("""
            CREATE TABLE semantic_claim (
                id TEXT PRIMARY KEY,
                owner_id TEXT,
                subject TEXT,
                predicate TEXT,
                object_value TEXT,
                status TEXT DEFAULT 'active',
                created_at TEXT,
                valid_from TEXT,
                valid_to TEXT,
                superseded_by TEXT,
                confidence REAL DEFAULT 0.5,
                temporal_marker TEXT
            )
        """)

    def _get_db(self, owner_id):
        return self.conn

    def add_claim(self, **kwargs):
        self.conn.execute(
            """INSERT INTO semantic_claim
               (id, owner_id, subject, predicate, object_value, status,
                created_at, valid_from, valid_to, superseded_by, confidence, temporal_marker)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            (
                kwargs["id"], kwargs.get("owner_id", "default"),
                kwargs["subject"], kwargs["predicate"], kwargs["value"],
                kwargs.get("status", "active"),
                kwargs.get("created_at", "2024-01-01"),
                kwargs.get("valid_from"), kwargs.get("valid_to"),
                kwargs.get("superseded_by"),
                kwargs.get("confidence", 0.5),
                kwargs.get("temporal_marker"),
            ),
        )
        self.conn.commit()


class TestBeliefHistory:
    @pytest.mark.asyncio
    async def test_single_active_claim(self):
        storage = _FakeStorage()
        storage.add_claim(id="c1", subject="user", predicate="lives_in", value="Bangkok")

        history = await get_belief_history(storage, "user", "lives_in")
        assert history.current_value == "Bangkok"
        assert history.change_count == 1
        assert history.changes[0].claim_id == "c1"

    @pytest.mark.asyncio
    async def test_supersession_chain(self):
        storage = _FakeStorage()
        storage.add_claim(
            id="c1", subject="user", predicate="lives_in", value="SF",
            status="superseded", superseded_by="c2",
            created_at="2023-01-01", valid_to="2024-01-01",
        )
        storage.add_claim(
            id="c2", subject="user", predicate="lives_in", value="Tokyo",
            status="superseded", superseded_by="c3",
            created_at="2024-01-01", valid_to="2024-06-01",
        )
        storage.add_claim(
            id="c3", subject="user", predicate="lives_in", value="Bangkok",
            status="active", created_at="2024-06-01",
        )

        history = await get_belief_history(storage, "user", "lives_in")
        assert history.current_value == "Bangkok"
        assert history.change_count == 3
        # Ordered by created_at DESC
        assert history.changes[0].value == "Bangkok"
        assert history.changes[1].value == "Tokyo"
        assert history.changes[2].value == "SF"

    @pytest.mark.asyncio
    async def test_no_matching_claims(self):
        storage = _FakeStorage()
        history = await get_belief_history(storage, "user", "nonexistent")
        assert history.change_count == 0
        assert history.current_value is None

    @pytest.mark.asyncio
    async def test_to_dict(self):
        history = BeliefHistory(
            subject="user", predicate="likes",
            current_value="coffee",
            changes=[
                BeliefChange(
                    claim_id="c1", subject="user", predicate="likes",
                    value="coffee", status="active",
                ),
            ],
        )
        d = history.to_dict()
        assert d["subject"] == "user"
        assert d["current_value"] == "coffee"
        assert len(d["changes"]) == 1

    @pytest.mark.asyncio
    async def test_entity_changes(self):
        storage = _FakeStorage()
        # lives_in has a change
        storage.add_claim(id="c1", subject="user", predicate="lives_in", value="SF", status="superseded")
        storage.add_claim(id="c2", subject="user", predicate="lives_in", value="Bangkok")
        # job has no change (single claim)
        storage.add_claim(id="c3", subject="user", predicate="job", value="engineer")

        histories = await get_belief_changes_for_entity(storage, "user")
        # Only lives_in should appear (has >1 change)
        assert len(histories) == 1
        assert histories[0].predicate == "lives_in"
