import pytest

from core.protocol import SettingsAction
from sdk.interface import UserSettings
from sdk.prototype_state import PrototypeStateStore


@pytest.mark.asyncio
async def test_get_or_create_user_is_stable_per_surface_identity():
    store = PrototypeStateStore()

    first = await store.get_or_create_user("@alice:example.org", "matrix", "Alice")
    second = await store.get_or_create_user("@alice:example.org", "matrix")

    assert first.user_id == "usr-matrix-@alice:example.org"
    assert first.is_new is True
    assert store._users["matrix:@alice:example.org"].is_new is False

    first.display_name = "Mallory"
    first.is_new = False

    assert second.user_id == first.user_id
    assert second.is_new is False
    assert second.display_name == "Alice"
    assert store._users["matrix:@alice:example.org"].display_name == "Alice"
    assert store._users["matrix:@alice:example.org"].is_new is False


@pytest.mark.asyncio
async def test_settings_defaults_match_existing_mock_shape():
    store = PrototypeStateStore()

    settings = await store.get_settings("usr-matrix-@alice:example.org")

    assert isinstance(settings, UserSettings)
    assert settings.skills == {
        "web-search": True,
        "fetch-url": True,
        "email": False,
        "browser": False,
        "image-gen": False,
        "files": True,
    }
    assert settings.safety == {
        "email-send": True,
        "file-delete": True,
        "social-post": True,
    }
    assert settings.soul == {"name": "Лямбда", "instructions": ""}
    assert settings.plan == {"name": "Beta", "tokens_used": 0, "tokens_limit": 1000}


@pytest.mark.asyncio
async def test_get_settings_returns_connectors_copy():
    store = PrototypeStateStore()
    store._settings["usr-matrix-@alice:example.org"] = {
        "connectors": {"github": {"enabled": True}},
    }

    settings = await store.get_settings("usr-matrix-@alice:example.org")
    settings.connectors["github"]["enabled"] = False
    settings.connectors["slack"] = {"enabled": True}

    assert store._settings["usr-matrix-@alice:example.org"]["connectors"] == {
        "github": {"enabled": True},
    }


@pytest.mark.asyncio
async def test_update_settings_supports_toggle_skill_and_setters():
    store = PrototypeStateStore()

    await store.update_settings(
        "usr-matrix-@alice:example.org",
        SettingsAction(action="toggle_skill", payload={"skill": "browser", "enabled": True}),
    )
    await store.update_settings(
        "usr-matrix-@alice:example.org",
        SettingsAction(action="set_soul", payload={"field": "instructions", "value": "Be concise"}),
    )
    await store.update_settings(
        "usr-matrix-@alice:example.org",
        SettingsAction(action="set_safety", payload={"trigger": "social-post", "enabled": False}),
    )

    settings = await store.get_settings("usr-matrix-@alice:example.org")

    assert settings.skills["browser"] is True
    assert settings.skills["web-search"] is True
    assert settings.soul["instructions"] == "Be concise"
    assert settings.safety["social-post"] is False


@pytest.mark.asyncio
async def test_add_saved_session_appends_named_entries():
    store = PrototypeStateStore()

    await store.add_saved_session(
        "usr-matrix-@alice:example.org",
        "alpha",
        source_context_id="ctx-room-1",
    )
    await store.add_saved_session("usr-matrix-@alice:example.org", "beta")

    sessions = await store.list_saved_sessions("usr-matrix-@alice:example.org")

    assert [session["name"] for session in sessions] == ["alpha", "beta"]
    assert all("created_at" in session for session in sessions)
    assert sessions[0]["source_context_id"] == "ctx-room-1"


@pytest.mark.asyncio
async def test_list_saved_sessions_returns_copy():
    store = PrototypeStateStore()

    await store.add_saved_session("usr-matrix-@alice:example.org", "alpha")

    sessions = await store.list_saved_sessions("usr-matrix-@alice:example.org")
    sessions.append({"name": "tampered", "created_at": "never"})

    stored = await store.list_saved_sessions("usr-matrix-@alice:example.org")

    assert [session["name"] for session in stored] == ["alpha"]


@pytest.mark.asyncio
async def test_get_last_tokens_used_defaults_to_zero():
    store = PrototypeStateStore()

    assert await store.get_last_tokens_used_for_context("ctx-room-1") == 0


@pytest.mark.asyncio
async def test_live_tokens_used_are_scoped_per_context():
    store = PrototypeStateStore()

    await store.set_last_tokens_used_for_context("ctx-room-1", 321)
    await store.set_last_tokens_used_for_context("ctx-room-2", 654)

    assert await store.get_last_tokens_used_for_context("ctx-room-1") == 321
    assert await store.get_last_tokens_used_for_context("ctx-room-2") == 654


@pytest.mark.asyncio
async def test_current_session_roundtrip_is_scoped_per_context():
    store = PrototypeStateStore()

    assert await store.get_current_session_for_context("ctx-room-1") is None
    assert await store.get_current_session_for_context("ctx-room-2") is None

    await store.set_current_session_for_context("ctx-room-1", "session-1")
    await store.set_current_session_for_context("ctx-room-2", "session-2")

    assert await store.get_current_session_for_context("ctx-room-1") == "session-1"
    assert await store.get_current_session_for_context("ctx-room-2") == "session-2"


@pytest.mark.asyncio
async def test_clear_current_session_removes_only_target_context():
    store = PrototypeStateStore()

    await store.set_current_session_for_context("ctx-room-1", "session-1")
    await store.set_current_session_for_context("ctx-room-2", "session-2")

    await store.clear_current_session_for_context("ctx-room-1")

    assert await store.get_current_session_for_context("ctx-room-1") is None
    assert await store.get_current_session_for_context("ctx-room-2") == "session-2"


@pytest.mark.asyncio
async def test_saved_sessions_remain_user_scoped_separate_from_live_context_state():
    store = PrototypeStateStore()

    await store.set_current_session_for_context("ctx-room-1", "room-session")
    await store.set_last_tokens_used_for_context("ctx-room-1", 77)
    await store.add_saved_session("usr-matrix-@alice:example.org", "alpha")

    sessions = await store.list_saved_sessions("usr-matrix-@alice:example.org")

    assert [session["name"] for session in sessions] == ["alpha"]
    assert all(isinstance(session["created_at"], str) for session in sessions)
    assert await store.get_current_session_for_context("ctx-room-1") == "room-session"
    assert await store.get_last_tokens_used_for_context("ctx-room-1") == 77
