import pytest

from amcs.store.sqlite import SQLiteEventStore
from amcs.types import EventValidationError, build_event_envelope


def _event(agent_id: str, msg: str, ts: str) -> dict:
    return build_event_envelope(
        agent_id=agent_id,
        event_type="interaction.append",
        payload={"message": msg},
        timestamp=ts,
    )


def test_sqlite_store_assigns_sequences_per_agent(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))

    r1 = store.append_event("agent-a", _event("agent-a", "one", "2026-02-19T00:00:01Z"))
    r2 = store.append_event("agent-a", _event("agent-a", "two", "2026-02-19T00:00:02Z"))
    r3 = store.append_event("agent-a", _event("agent-a", "three", "2026-02-19T00:00:03Z"))
    rb1 = store.append_event("agent-b", _event("agent-b", "b-one", "2026-02-19T00:00:01Z"))

    assert [r1["sequence"], r2["sequence"], r3["sequence"]] == [1, 2, 3]
    assert rb1["sequence"] == 1


def test_sqlite_store_persists_roots_and_roots_change(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))

    r1 = store.append_event("agent-a", _event("agent-a", "one", "2026-02-19T00:00:01Z"))
    r2 = store.append_event("agent-a", _event("agent-a", "two", "2026-02-19T00:00:02Z"))

    assert r1["memory_root"] != r2["memory_root"]
    assert store.get_memory_root("agent-a", 1) == r1["memory_root"]
    assert store.get_memory_root("agent-a") == r2["memory_root"]


def test_sqlite_store_range_queries(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))

    store.append_event("agent-a", _event("agent-a", "one", "2026-02-19T00:00:01Z"))
    store.append_event("agent-a", _event("agent-a", "two", "2026-02-19T00:00:02Z"))
    store.append_event("agent-a", _event("agent-a", "three", "2026-02-19T00:00:03Z"))

    events = store.get_events("agent-a", from_seq=2, to_seq=3)

    assert [item["sequence"] for item in events] == [2, 3]
    assert [item["event"]["payload"]["message"] for item in events] == ["two", "three"]


def test_sqlite_store_event_json_includes_sequence(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))
    store.append_event("agent-a", _event("agent-a", "one", "2026-02-19T00:00:01Z"))

    first = store.get_events("agent-a", from_seq=1, to_seq=1)[0]
    assert first["event"]["sequence"] == 1
    assert '"sequence":1' in first["event_json"]


def test_sqlite_store_latest_sequence_and_hash_ranges(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))
    r1 = store.append_event("agent-a", _event("agent-a", "one", "2026-02-19T00:00:01Z"))
    r2 = store.append_event("agent-a", _event("agent-a", "two", "2026-02-19T00:00:02Z"))
    store.append_event("agent-a", _event("agent-a", "three", "2026-02-19T00:00:03Z"))

    assert store.get_latest_sequence("agent-a") == 3
    assert store.get_latest_sequence("agent-b") is None

    hashes = store.get_event_hashes("agent-a", from_seq=1, to_seq=2)
    assert hashes == [r1["event_hash"], r2["event_hash"]]


def test_sqlite_store_rejects_wrong_amcs_version(tmp_path) -> None:
    store = SQLiteEventStore(str(tmp_path / "events.db"))
    event = _event("agent-a", "one", "2026-02-19T00:00:01Z")
    event["amcs_version"] = "AMCS-0.2"

    with pytest.raises(EventValidationError):
        store.append_event("agent-a", event)


def test_sqlite_store_hardens_file_permissions_on_create(tmp_path) -> None:
    db_path = tmp_path / "secure-events.db"
    _ = SQLiteEventStore(str(db_path))
    mode = db_path.stat().st_mode & 0o777
    assert mode == 0o600
