"""Phase-2 phone-power server-side tools: places, contacts, SMS watch, routines.
Memory HTTP is a fake in-memory store; no network. Numbers must never leak."""
import phone_store
import tools

from test_phone_store import FakeMem


def _wire(monkeypatch):
    fake = FakeMem()
    monkeypatch.setattr(phone_store, "_mem_request", fake.request)
    return fake


# --- places ----------------------------------------------------------------
async def test_save_place_coords_then_get(monkeypatch):
    _wire(monkeypatch)
    out = await tools.execute("save_place",
                              {"label": "gym", "address_or_coords": "26.30,50.20"})
    assert "gym" in out.lower()
    got = await tools.execute("get_place", {"label": "gym"})
    assert "26.3" in got and "50.2" in got
    items = await phone_store.list_items(phone_store.KIND_PLACE)
    assert items[0]["lat"] == 26.30 and items[0]["lng"] == 50.20


async def test_save_place_address(monkeypatch):
    _wire(monkeypatch)
    await tools.execute("save_place",
                        {"label": "home", "address_or_coords": "12 Palm St"})
    got = await tools.execute("get_place", {"label": "home"})
    assert "12 Palm St" in got
    assert "No place" in await tools.execute("get_place", {"label": "nowhere"})


async def test_list_places(monkeypatch):
    _wire(monkeypatch)
    assert "No places" in await tools.execute("list_places", {})
    await tools.execute("save_place",
                        {"label": "office", "address_or_coords": "Tower 1"})
    assert "office" in await tools.execute("list_places", {})


# --- contacts (numbers must stay private) ----------------------------------
async def test_save_contact_never_echoes_number(monkeypatch):
    _wire(monkeypatch)
    num = "0501234567"
    out = await tools.execute("save_contact",
                              {"name": "father", "number": num,
                               "relation": "family"})
    assert "father" in out.lower()
    assert num not in out                    # full number never echoed
    got = await tools.execute("get_contact", {"name": "father"})
    assert num not in got
    assert tools.mask_number(num) in got     # masked tail only (never full)
    lst = await tools.execute("list_contacts", {})
    assert num not in lst and "father" in lst.lower()
    # ...but the real number IS persisted for the device to dial
    c = await phone_store.get_item(phone_store.KIND_CONTACT, "father")
    assert c["number"] == num


async def test_get_contact_missing(monkeypatch):
    _wire(monkeypatch)
    assert "No contact" in await tools.execute("get_contact", {"name": "ghost"})


# --- SMS watch-list --------------------------------------------------------
async def test_sms_watch_add_list_remove(monkeypatch):
    _wire(monkeypatch)
    await tools.execute("sms_watch_add", {"sender": "SNB-AlAhli"})
    await tools.execute("sms_watch_add", {"sender": "*"})
    lst = await tools.execute("sms_watch_list", {})
    assert "SNB-AlAhli" in lst and "*" in lst
    rm = await tools.execute("sms_watch_remove", {"sender": "SNB-AlAhli"})
    assert "Stopped" in rm
    assert "SNB-AlAhli" not in await tools.execute("sms_watch_list", {})


# --- routines (+ change hook) ----------------------------------------------
async def test_routine_create_validates(monkeypatch):
    _wire(monkeypatch)
    bad = await tools.execute("routine_create", {
        "name": "x", "trigger": {"type": "time"},          # missing 'at'
        "action": {"type": "speak_brief", "brief": "tasks"}})
    assert "failed" in bad.lower()
    assert await phone_store.list_items(phone_store.KIND_ROUTINE) == []


async def test_routine_create_list_cancel_fires_hook(monkeypatch):
    _wire(monkeypatch)
    hits = []

    async def hook():
        hits.append(1)
    tools.set_routine_hook(hook)
    try:
        ok = await tools.execute("routine_create", {
            "name": "morning brief",
            "trigger": {"type": "time", "at": "07:00", "days": ["daily"]},
            "action": {"type": "speak_brief", "brief": "tasks"}})
        assert "set" in ok.lower()
        lst = await tools.execute("routine_list", {})
        assert "morning brief" in lst and "07:00" in lst
        cancel = await tools.execute("routine_cancel", {"name": "morning brief"})
        assert "Cancelled" in cancel
        assert len(hits) == 2                 # create + cancel each reschedule
    finally:
        tools.set_routine_hook(None)
