"""Regression tests: calendar tool respects the user's configured timezone."""

from datetime import timezone
from unittest.mock import AsyncMock, patch

import pytest


@pytest.mark.asyncio
async def test_create_event_all_day_bare_date_interprets_local_midnight():
    """Bare date like '2026-09-30' for a NY user = 2026-09-30 00:00 NY,
    stored as 2026-09-30 04:00 UTC — NOT 2026-09-30 00:00 UTC (which would
    be 2026-09-29 19:00 NY and land on the wrong day)."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1, **{k: v for k, v in kwargs.items() if not callable(v)}}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={"title": "Birthday", "start": "2026-09-30"},
        )

    assert result["success"] is True
    start_dt = captured["start_dt"]
    assert start_dt.tzinfo is not None
    # Converted to UTC: 00:00 NY (EDT, UTC-4) == 04:00 UTC on the same day
    utc = start_dt.astimezone(timezone.utc)
    assert (utc.year, utc.month, utc.day) == (2026, 9, 30)
    assert utc.hour == 4  # EDT offset; would be 5 in EST
    assert captured["all_day"] is True


@pytest.mark.asyncio
async def test_create_event_naive_datetime_is_user_local():
    """'2026-03-15T14:30' for a NY user means 2:30pm NY, not 2:30pm UTC."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        await create_event_tool(
            user_id=1,
            arguments={"title": "Meeting", "start": "2026-03-15T14:30"},
        )

    utc = captured["start_dt"].astimezone(timezone.utc)
    # 14:30 NY on 2026-03-15 (after DST start) = 18:30 UTC
    assert (utc.year, utc.month, utc.day, utc.hour, utc.minute) == (2026, 3, 15, 18, 30)


@pytest.mark.asyncio
async def test_create_event_explicit_offset_is_respected():
    """Model-supplied timezone offsets must not be overridden by user TZ."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        await create_event_tool(
            user_id=1,
            arguments={"title": "Meeting", "start": "2026-03-15T14:30+00:00"},
        )

    utc = captured["start_dt"].astimezone(timezone.utc)
    assert (utc.hour, utc.minute) == (14, 30)


@pytest.mark.asyncio
async def test_list_events_bare_date_range_covers_local_day():
    """date_from/date_to as bare dates should cover the full LOCAL day."""
    from fabledassistant.services.tools.calendar import list_events_tool

    captured = {}

    async def fake_list_events(*, user_id, date_from, date_to):
        captured["date_from"] = date_from
        captured["date_to"] = date_to
        return []

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_list_events",
        side_effect=fake_list_events,
    ):
        await list_events_tool(
            user_id=1,
            arguments={"date_from": "2026-09-30", "date_to": "2026-09-30"},
        )

    df = captured["date_from"].astimezone(timezone.utc)
    dt = captured["date_to"].astimezone(timezone.utc)
    # 2026-09-30 00:00 NY (EDT) = 04:00 UTC same day
    assert (df.year, df.month, df.day, df.hour) == (2026, 9, 30, 4)
    # 2026-09-30 23:59:59 NY (EDT) = 03:59:59 UTC next day
    assert (dt.year, dt.month, dt.day, dt.hour) == (2026, 10, 1, 3)


# ── Split date/time field tests (durable shape) ──────────────────────────────
#
# These exercise the start_date + start_time path that the model is now
# steered toward. The split-field shape is structurally immune to the
# class of bugs where a model emits a TZ-tagged combined datetime that
# the parser correctly honors but lands on the wrong calendar day for
# negative-offset users.


@pytest.mark.asyncio
async def test_create_event_split_fields_friday_8am_no_drift_eastern():
    """The reported bug: 'next Friday at 8am' for a NY user must land on
    2026-05-01 08:00 NY, never 04-30 19:00. With split fields the model
    can't TZ-tag the date string, so the calendar day is fixed."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "Meeting",
                "start_date": "2026-05-01",
                "start_time": "08:00",
            },
        )

    assert result["success"] is True
    utc = captured["start_dt"].astimezone(timezone.utc)
    # 08:00 NY (EDT, UTC-4) on 2026-05-01 = 12:00 UTC same day
    assert (utc.year, utc.month, utc.day, utc.hour, utc.minute) == (2026, 5, 1, 12, 0)
    assert captured["all_day"] is False


@pytest.mark.asyncio
async def test_create_event_split_fields_no_drift_pacific():
    """Same scenario for a UTC-8 user — the calendar day must be 5/1
    regardless of how big the offset gets."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/Los_Angeles")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        await create_event_tool(
            user_id=1,
            arguments={
                "title": "Standup",
                "start_date": "2026-05-01",
                "start_time": "08:00",
            },
        )

    utc = captured["start_dt"].astimezone(timezone.utc)
    # 08:00 LA (PDT, UTC-7) = 15:00 UTC same day
    assert (utc.year, utc.month, utc.day, utc.hour) == (2026, 5, 1, 15)


@pytest.mark.asyncio
async def test_create_event_split_fields_no_drift_positive_offset():
    """A positive-offset user (Tokyo, UTC+9) — 08:00 Tokyo on 2026-05-01
    is 23:00 UTC on 2026-04-30, but the local calendar day must still be
    stored as 2026-05-01 from the user's perspective."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("Asia/Tokyo")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        await create_event_tool(
            user_id=1,
            arguments={
                "title": "Sync",
                "start_date": "2026-05-01",
                "start_time": "08:00",
            },
        )

    utc = captured["start_dt"].astimezone(timezone.utc)
    # 08:00 Tokyo (UTC+9) = 23:00 UTC previous day; the round-trip back
    # to Tokyo TZ recovers 2026-05-01 08:00.
    assert (utc.year, utc.month, utc.day, utc.hour) == (2026, 4, 30, 23)
    tokyo = captured["start_dt"].astimezone(__import__("zoneinfo").ZoneInfo("Asia/Tokyo"))
    assert (tokyo.year, tokyo.month, tokyo.day, tokyo.hour) == (2026, 5, 1, 8)


@pytest.mark.asyncio
async def test_create_event_split_date_only_is_all_day():
    """Omitting start_time means the event is all-day; cache row uses
    local midnight."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        await create_event_tool(
            user_id=1,
            arguments={"title": "Birthday", "start_date": "2026-09-30"},
        )

    assert captured["all_day"] is True
    utc = captured["start_dt"].astimezone(timezone.utc)
    assert (utc.year, utc.month, utc.day, utc.hour) == (2026, 9, 30, 4)


@pytest.mark.asyncio
async def test_create_event_split_rejects_tz_suffix_in_date():
    """The whole point of split fields: a TZ suffix on the date string
    must be rejected, not silently honored."""
    from fabledassistant.services.tools.calendar import create_event_tool

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={"title": "x", "start_date": "2026-05-01Z", "start_time": "08:00"},
        )

    assert result["success"] is False
    assert "YYYY-MM-DD" in result["error"]


@pytest.mark.asyncio
async def test_create_event_split_rejects_tz_suffix_in_time():
    """A TZ suffix on the time string must also be rejected."""
    from fabledassistant.services.tools.calendar import create_event_tool

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={"title": "x", "start_date": "2026-05-01", "start_time": "08:00 UTC"},
        )

    assert result["success"] is False
    assert "HH:MM" in result["error"]


@pytest.mark.asyncio
async def test_create_event_legacy_combined_start_still_works():
    """Backcompat: saved tool-call payloads using the old `start` field
    must still produce the same UTC datetime as before."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={"title": "Legacy", "start": "2026-05-01T08:00"},
        )

    assert result["success"] is True
    utc = captured["start_dt"].astimezone(timezone.utc)
    assert (utc.year, utc.month, utc.day, utc.hour) == (2026, 5, 1, 12)


@pytest.mark.asyncio
async def test_update_event_split_fields_reschedule_no_drift():
    """update_event with split fields must drift no calendar day either."""
    from fabledassistant.services.tools.calendar import update_event_tool

    captured = {}

    async def fake_find(*, user_id, query):
        ev = AsyncMock()
        ev.id = 99
        ev.title = "Coffee"
        return [ev]

    async def fake_update(*, user_id, event_id, **fields):
        captured.update(fields)
        ev = AsyncMock()
        ev.to_dict.return_value = {"id": event_id, **fields}
        return ev

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.find_events_by_query",
        side_effect=fake_find,
    ), patch(
        "fabledassistant.services.tools.calendar.events_update_event",
        side_effect=fake_update,
    ):
        result = await update_event_tool(
            user_id=1,
            arguments={
                "query": "Coffee",
                "start_date": "2026-05-01",
                "start_time": "08:00",
            },
        )

    assert result["success"] is True
    utc = captured["start_dt"].astimezone(timezone.utc)
    assert (utc.year, utc.month, utc.day, utc.hour) == (2026, 5, 1, 12)


# ── expected_weekday verification (catches "this Friday" → Thursday bugs) ────


@pytest.mark.asyncio
async def test_create_event_expected_weekday_match_succeeds():
    """When expected_weekday agrees with the resolved local date's
    weekday, the event is created normally."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "Meeting",
                "start_date": "2026-05-01",  # is a Friday
                "start_time": "08:00",
                "expected_weekday": "friday",
            },
        )

    assert result["success"] is True
    assert captured["start_dt"] is not None


@pytest.mark.asyncio
async def test_create_event_expected_weekday_mismatch_rejects_and_names_actual():
    """The reported failure mode: model picks Thursday and calls it
    Friday. With expected_weekday set, the create is rejected and the
    error names the actual weekday so the model can self-correct."""
    from fabledassistant.services.tools.calendar import create_event_tool

    create_called = False

    async def fake_create_event(**kwargs):
        nonlocal create_called
        create_called = True
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "Dentist",
                "start_date": "2026-04-30",  # Thursday
                "start_time": "08:00",
                "expected_weekday": "friday",
            },
        )

    assert result["success"] is False
    assert "Thursday" in result["error"]
    assert "Friday" in result["error"]
    # Critical: the event must NOT have been created when the check failed.
    assert create_called is False


@pytest.mark.asyncio
async def test_create_event_expected_weekday_omitted_skips_check():
    """Backcompat: when expected_weekday isn't passed, no validation
    runs — the existing create flow is unchanged."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "x",
                "start_date": "2026-04-30",
                "start_time": "08:00",
            },
        )

    assert result["success"] is True


@pytest.mark.asyncio
async def test_create_event_expected_weekday_invalid_value_rejects():
    """Garbage in expected_weekday produces a clear validation error,
    not a silent pass."""
    from fabledassistant.services.tools.calendar import create_event_tool

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "x",
                "start_date": "2026-05-01",
                "start_time": "08:00",
                "expected_weekday": "fri",  # abbreviation not accepted
            },
        )

    assert result["success"] is False
    assert "weekday" in result["error"].lower()


@pytest.mark.asyncio
async def test_update_event_expected_weekday_mismatch_rejects():
    """update_event must enforce the same weekday check on reschedules."""
    from fabledassistant.services.tools.calendar import update_event_tool

    update_called = False

    async def fake_find(*, user_id, query):
        ev = AsyncMock()
        ev.id = 99
        ev.title = "Coffee"
        return [ev]

    async def fake_update(*, user_id, event_id, **fields):
        nonlocal update_called
        update_called = True
        ev = AsyncMock()
        ev.to_dict.return_value = {"id": event_id}
        return ev

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("America/New_York")),
    ), patch(
        "fabledassistant.services.tools.calendar.find_events_by_query",
        side_effect=fake_find,
    ), patch(
        "fabledassistant.services.tools.calendar.events_update_event",
        side_effect=fake_update,
    ):
        result = await update_event_tool(
            user_id=1,
            arguments={
                "query": "Coffee",
                "start_date": "2026-04-30",  # Thursday
                "start_time": "08:00",
                "expected_weekday": "friday",
            },
        )

    assert result["success"] is False
    assert "Thursday" in result["error"]
    assert update_called is False


# ── Multi-match disambiguation (Fable #161) ──────────────────────────────────


@pytest.mark.asyncio
async def test_update_event_refuses_ambiguous_query_with_candidates():
    """The reported failure: model called update_event(query='Appointment')
    when two events matched. Pre-fix: silently mutated matches[0] (the
    wrong event). Post-fix: returns success=False with a candidates list
    so the model can pick the right one."""
    from fabledassistant.services.tools.calendar import update_event_tool

    # Two events both matching "Appointment"
    ev_a = AsyncMock()
    ev_a.id = 2
    ev_a.title = "Appointment"
    ev_a.start_dt = __import__("datetime").datetime(2026, 4, 30, 12, 0, tzinfo=timezone.utc)
    ev_a.location = ""
    ev_b = AsyncMock()
    ev_b.id = 15
    ev_b.title = "Appointment"
    ev_b.start_dt = __import__("datetime").datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
    ev_b.location = "Dentist"

    update_called = False

    async def fake_find(*, user_id, query):
        return [ev_a, ev_b]

    async def fake_update(*, user_id, event_id, **fields):
        nonlocal update_called
        update_called = True
        return AsyncMock()

    with patch(
        "fabledassistant.services.tools.calendar.find_events_by_query",
        side_effect=fake_find,
    ), patch(
        "fabledassistant.services.tools.calendar.events_update_event",
        side_effect=fake_update,
    ):
        result = await update_event_tool(
            user_id=1,
            arguments={"query": "Appointment", "title": "Dentist"},
        )

    assert result["success"] is False
    assert "Found 2 events" in result["error"]
    assert "event_id" in result["error"].lower()
    assert "candidates" in result
    candidate_ids = [c["id"] for c in result["candidates"]]
    assert candidate_ids == [2, 15]
    # Critical: nothing was mutated.
    assert update_called is False


@pytest.mark.asyncio
async def test_update_event_with_event_id_skips_query_lookup():
    """Once the model picks a candidate via event_id, the call proceeds
    against that exact event — no query, no ambiguity."""
    from fabledassistant.services.tools.calendar import update_event_tool

    # find_events_by_query should NOT be called when event_id is supplied
    find_called = False

    async def fake_find(*, user_id, query):
        nonlocal find_called
        find_called = True
        return []

    target = AsyncMock()
    target.id = 15
    target.title = "Appointment"
    target.start_dt = __import__("datetime").datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
    target.location = ""

    async def fake_get_event(*, user_id, event_id):
        return target if event_id == 15 else None

    captured = {}

    async def fake_update(*, user_id, event_id, **fields):
        captured["event_id"] = event_id
        captured.update(fields)
        ev = AsyncMock()
        ev.to_dict.return_value = {"id": event_id, **fields}
        return ev

    with patch(
        "fabledassistant.services.tools.calendar.find_events_by_query",
        side_effect=fake_find,
    ), patch(
        "fabledassistant.services.events.get_event",
        side_effect=fake_get_event,
    ), patch(
        "fabledassistant.services.tools.calendar.events_update_event",
        side_effect=fake_update,
    ):
        result = await update_event_tool(
            user_id=1,
            arguments={"event_id": 15, "title": "Dentist: Permanent Crown Fitting"},
        )

    assert result["success"] is True
    assert captured["event_id"] == 15
    assert captured["title"] == "Dentist: Permanent Crown Fitting"
    assert find_called is False


@pytest.mark.asyncio
async def test_update_event_with_event_id_not_found_returns_error():
    """A bad event_id (non-existent) must surface clearly, not silently
    fall back to query-based lookup."""
    from fabledassistant.services.tools.calendar import update_event_tool

    async def fake_get_event(*, user_id, event_id):
        return None

    with patch(
        "fabledassistant.services.events.get_event",
        side_effect=fake_get_event,
    ):
        result = await update_event_tool(
            user_id=1,
            arguments={"event_id": 999, "title": "anything"},
        )

    assert result["success"] is False
    assert "999" in result["error"]
    assert "No event found" in result["error"]


@pytest.mark.asyncio
async def test_update_event_neither_query_nor_event_id_returns_error():
    """Calling update_event with neither identifier is a usage error."""
    from fabledassistant.services.tools.calendar import update_event_tool

    result = await update_event_tool(user_id=1, arguments={"title": "x"})
    assert result["success"] is False
    assert "query or event_id" in result["error"]


@pytest.mark.asyncio
async def test_delete_event_refuses_ambiguous_query_with_candidates():
    """delete_event must enforce the same disambiguation. Costly to get
    wrong — silent matches[0] would delete the wrong event entirely."""
    from fabledassistant.services.tools.calendar import delete_event_tool

    ev_a = AsyncMock()
    ev_a.id = 2; ev_a.title = "Appointment"
    ev_a.start_dt = __import__("datetime").datetime(2026, 4, 30, 12, 0, tzinfo=timezone.utc)
    ev_a.location = ""
    ev_b = AsyncMock()
    ev_b.id = 15; ev_b.title = "Appointment"
    ev_b.start_dt = __import__("datetime").datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc)
    ev_b.location = "Dentist"

    delete_called = False

    async def fake_find(*, user_id, query):
        return [ev_a, ev_b]

    async def fake_delete(*, user_id, event_id):
        nonlocal delete_called
        delete_called = True

    with patch(
        "fabledassistant.services.tools.calendar.find_events_by_query",
        side_effect=fake_find,
    ), patch(
        "fabledassistant.services.tools.calendar.events_delete_event",
        side_effect=fake_delete,
    ):
        result = await delete_event_tool(
            user_id=1, arguments={"query": "Appointment"},
        )

    assert result["success"] is False
    assert len(result["candidates"]) == 2
    # Most important assertion: nothing was actually deleted.
    assert delete_called is False


@pytest.mark.asyncio
async def test_create_event_weekday_check_uses_local_not_utc():
    """The weekday check must use the LOCAL date, not the UTC date.
    A late-evening Friday event in Tokyo (UTC+9) crosses midnight UTC,
    so a UTC-day check would call it Saturday — but the user's calendar
    says Friday. The check must respect the user's local view."""
    from fabledassistant.services.tools.calendar import create_event_tool

    captured = {}

    async def fake_create_event(**kwargs):
        captured.update(kwargs)
        event = AsyncMock()
        event.to_dict.return_value = {"id": 1}
        return event

    with patch(
        "fabledassistant.services.tools.calendar.get_user_tz",
        AsyncMock(return_value=__import__("zoneinfo").ZoneInfo("Asia/Tokyo")),
    ), patch(
        "fabledassistant.services.tools.calendar.events_create_event",
        side_effect=fake_create_event,
    ):
        result = await create_event_tool(
            user_id=1,
            arguments={
                "title": "Friday night",
                "start_date": "2026-05-01",  # Friday in Tokyo
                "start_time": "23:00",       # 14:00 UTC same day; safe
                "expected_weekday": "friday",
            },
        )

    assert result["success"] is True
