# retoor <retoor@molodetz.nl>

from devplacepy import database
from devplacepy.services.manager import service_manager
from devplacepy.services.devii import DeviiService
from devplacepy.services.devii.session import _parse_topic


def _hub():
    if service_manager.get_service("devii") is None:
        service_manager.register(DeviiService())
    svc = service_manager.get_service("devii")
    return svc.hub(), svc


def _session(channel, owner_id):
    hub, svc = _hub()
    return hub.get_or_create(
        "guest", owner_id, "guest", "", svc.instance_base_url(), is_admin=False, channel=channel
    )


def _tool_names(session):
    return {t["function"]["name"] for t in session.tools}


def test_docs_channel_restricts_to_search_docs(local_db):
    docs = _session("docs", "sess-docs-tools")
    assert _tool_names(docs) == {"search_docs"}


def test_docs_channel_uses_docii_prompt_without_behavior_header(local_db):
    docs = _session("docs", "sess-docs-prompt")
    prompt = docs._compose_system_prompt()
    assert prompt.startswith("You are Docii")
    assert "search_docs" in prompt
    assert "TRUTH RULES AND BEHAVIOR" not in prompt


def test_main_channel_keeps_full_catalog_and_behavior(local_db):
    main = _session("main", "sess-main")
    names = _tool_names(main)
    assert "search_docs" in names
    assert "ui_prompt" in names
    assert "ui_cancel" in names
    assert len(names) > 1
    prompt = main._compose_system_prompt()
    assert "TRUTH RULES AND BEHAVIOR" in prompt
    assert "CHANNEL: site-chat" in prompt
    assert "Interactive asks (CA-IWP)" in prompt


def test_docs_channel_excludes_ui_prompt(local_db):
    docs = _session("docs", "sess-docs-ui")
    assert "ui_prompt" not in _tool_names(docs)


def test_telegram_channel_includes_ui_prompt(local_db):
    tg = _session("telegram", "sess-tg-ui")
    names = _tool_names(tg)
    assert "ui_prompt" in names
    prompt = tg._compose_system_prompt()
    assert "CHANNEL: telegram" in prompt


def test_guest_main_has_ui_prompt_without_pref_tools(local_db):
    main = _session("main", "sess-guest-ui")
    names = _tool_names(main)
    assert "ui_prompt" in names
    assert "interactions_get" not in names
    assert "interactions_set" not in names


def test_scheduled_tasks_only_ever_resolve_a_main_channel_session(local_db):
    hub, svc = _hub()
    channels = []
    original = hub.get_or_create

    def capture(*args, **kwargs):
        channels.append(kwargs.get("channel"))
        return original(*args, **kwargs)

    hub.get_or_create = capture
    try:
        row = {"owner_kind": "user", "owner_id": "sess-docs-sched"}
        local_db["users"].insert(
            {
                "uid": "sess-docs-sched",
                "username": "sched-owner",
                "terms_version": "1",
                "role": "Admin",
                "api_key": "k",
                "deleted_at": None,
                "created_at": "2099-01-01T00:00:00",
            }
        )
        database.invalidate_admins_cache()
        svc._resolve_task_owner(row)
    finally:
        hub.get_or_create = original
    assert channels == ["main"]


def test_user_docs_channel_uses_ephemeral_stores(local_db):
    hub, svc = _hub()
    base = svc.instance_base_url()
    main = hub.get_or_create(
        "user", "u-iso", "u", "", base, is_admin=False, channel="main"
    )
    docs = hub.get_or_create(
        "user", "u-iso", "u", "", base, is_admin=False, channel="docs"
    )
    assert main.store._db is database.db
    assert docs.store._db is not database.db


def test_parse_topic_new_and_followup():
    assert _parse_topic('{"decision": "new", "reason": "unrelated"}') == (
        "new",
        "unrelated",
    )
    assert _parse_topic('{"decision": "follow_up", "reason": "same"}')[0] == "follow_up"


def test_parse_topic_extracts_embedded_json():
    decision, _ = _parse_topic('Sure. {"decision":"new","reason":"x"} done')
    assert decision == "new"


def test_parse_topic_defaults_to_followup_on_garbage():
    assert _parse_topic("not json at all")[0] == "follow_up"
    assert _parse_topic("")[0] == "follow_up"


def test_task_run_block_is_absent_outside_a_scheduled_run(local_db):
    session = _session("main", "sess-taskblock-off")
    assert "TASK RUN ENVIRONMENT" not in session._compose_system_prompt()


def _task_session(local_db, uid, role):
    from devplacepy.services.devii.tasks.context import task_run_scope

    hub, svc = _hub()
    local_db["users"].insert(
        {
            "uid": uid,
            "username": uid,
            "terms_version": "1",
            "role": role,
            "api_key": "k",
            "deleted_at": None,
            "created_at": "2099-01-01T00:00:00",
        }
    )
    database.invalidate_admins_cache()
    session = hub.get_or_create(
        "user", uid, uid, "", svc.instance_base_url(), channel="main"
    )
    with task_run_scope():
        return session._compose_system_prompt()


def test_member_session_is_told_it_may_not_nest_tasks(local_db):
    prompt = _task_session(local_db, "sess-task-member", "Member")
    assert "TASK RUN ENVIRONMENT" in prompt
    assert "may NOT schedule further work" in prompt


def test_administrator_session_is_told_it_may_nest_tasks(local_db):
    prompt = _task_session(local_db, "sess-task-admin", "Admin")
    assert "TASK RUN ENVIRONMENT" in prompt
    assert "you MAY" in prompt
