"""Tests for the journal prep filtering helpers added in #159."""

import datetime
from types import SimpleNamespace
from zoneinfo import ZoneInfo

import pytest


# ── _task_to_prep_dict ────────────────────────────────────────────────────────


def test_task_to_prep_dict_marks_overdue_with_days_count():
    from fabledassistant.services.journal_prep import _task_to_prep_dict

    today = datetime.date(2026, 4, 29)
    task = SimpleNamespace(
        id=2, title="Research Weston's ADHD Evaluation",
        status="todo", priority="high",
        due_date=datetime.date(2026, 2, 20),
    )
    d = _task_to_prep_dict(task, today)
    assert d["days_overdue"] == 68
    assert d["due_date"] == "2026-02-20"


def test_task_to_prep_dict_due_today_no_overdue_marker():
    from fabledassistant.services.journal_prep import _task_to_prep_dict

    today = datetime.date(2026, 4, 29)
    task = SimpleNamespace(
        id=10, title="Pick up dry cleaning",
        status="todo", priority="none",
        due_date=today,
    )
    d = _task_to_prep_dict(task, today)
    assert "days_overdue" not in d


def test_task_to_prep_dict_handles_no_due_date():
    from fabledassistant.services.journal_prep import _task_to_prep_dict

    task = SimpleNamespace(
        id=11, title="Long-running side project",
        status="in_progress", priority="medium",
        due_date=None,
    )
    d = _task_to_prep_dict(task, datetime.date(2026, 4, 29))
    assert d["due_date"] is None
    assert "days_overdue" not in d


# ── _filter_proximate_events ──────────────────────────────────────────────────


def test_filter_proximate_drops_far_future_recurring_event():
    """The reported failure: a recurring Birthday event with start_dt
    2026-09-29 surfaced in every daily prep. The proximity filter drops it."""
    from fabledassistant.services.journal_prep import _filter_proximate_events

    events = [
        {"id": 13, "title": "Birthday", "start_dt": "2026-09-29T00:00:00+00:00"},
    ]
    kept = _filter_proximate_events(
        events,
        day_date=datetime.date(2026, 4, 29),
        user_tz=ZoneInfo("America/New_York"),
    )
    assert kept == []


def test_filter_proximate_keeps_events_within_window():
    """Events within ±7 days of the prep date stay."""
    from fabledassistant.services.journal_prep import _filter_proximate_events

    events = [
        {"id": 1, "title": "Today", "start_dt": "2026-04-29T13:00:00+00:00"},
        {"id": 2, "title": "Tomorrow", "start_dt": "2026-04-30T12:00:00+00:00"},
        {"id": 3, "title": "Next week", "start_dt": "2026-05-05T15:00:00+00:00"},
        {"id": 4, "title": "Two weeks out", "start_dt": "2026-05-15T15:00:00+00:00"},
    ]
    kept = _filter_proximate_events(
        events,
        day_date=datetime.date(2026, 4, 29),
        user_tz=ZoneInfo("America/New_York"),
    )
    kept_ids = [e["id"] for e in kept]
    assert 1 in kept_ids
    assert 2 in kept_ids
    assert 3 in kept_ids
    assert 4 not in kept_ids


def test_filter_proximate_uses_local_date_not_utc():
    """An event at 04:30 UTC on 2026-04-30 = 00:30 local on 2026-04-30 in
    NY (EDT, UTC-4). Local date is 2026-04-30, delta from 2026-04-29 = 1
    day. Must NOT cross-classify based on UTC date alone."""
    from fabledassistant.services.journal_prep import _filter_proximate_events

    events = [
        {"id": 99, "title": "Late-night dentist", "start_dt": "2026-04-30T04:30:00+00:00"},
    ]
    kept = _filter_proximate_events(
        events,
        day_date=datetime.date(2026, 4, 29),
        user_tz=ZoneInfo("America/New_York"),
    )
    assert len(kept) == 1


def test_filter_proximate_keeps_unparseable_dates():
    """Bad date strings are kept rather than silently suppressing real
    events on a parser bug."""
    from fabledassistant.services.journal_prep import _filter_proximate_events

    events = [
        {"id": 50, "title": "Garbage", "start_dt": "not-a-date"},
        {"id": 51, "title": "Empty", "start_dt": ""},
        {"id": 52, "title": "Missing"},
    ]
    kept = _filter_proximate_events(
        events,
        day_date=datetime.date(2026, 4, 29),
        user_tz=ZoneInfo("America/New_York"),
    )
    assert len(kept) == 3


# ── _render_sections_for_prompt — overdue framing ────────────────────────────


def test_render_overdue_includes_staleness_duration():
    """The rendered prompt block must surface days_overdue so the LLM
    can frame stale tasks correctly."""
    from fabledassistant.services.journal_prep import _render_sections_for_prompt

    sections = {
        "tasks_due_today": [],
        "tasks_upcoming": [],
        "tasks_overdue": [{
            "id": 2, "title": "Research Weston's ADHD Evaluation",
            "status": "todo", "priority": "high",
            "due_date": "2026-02-20", "days_overdue": 68,
        }],
    }
    rendered = _render_sections_for_prompt(sections)
    assert "OVERDUE TASKS" in rendered
    # Unambiguous overdue phrasing (replaced the old "68 days ago", which the
    # model parroted alongside the header into a self-contradiction).
    assert "68 days overdue" in rendered
    assert "2026-02-20" in rendered
    # Crucially, NOT framed as due today.
    assert "DUE TODAY" not in rendered


def test_render_due_today_no_due_date_repetition():
    """Tasks in the DUE TODAY bucket don't need the (due 2026-04-29)
    parenthetical — the section header already says 'today'."""
    from fabledassistant.services.journal_prep import _render_sections_for_prompt

    sections = {
        "tasks_due_today": [{
            "id": 1, "title": "Pick up dry cleaning",
            "status": "todo", "priority": "none",
            "due_date": "2026-04-29",
        }],
        "tasks_upcoming": [],
        "tasks_overdue": [],
    }
    rendered = _render_sections_for_prompt(sections)
    assert "TASKS DUE TODAY" in rendered
    assert "Pick up dry cleaning" in rendered
    # The line itself shouldn't repeat the due date.
    line = next(
        (l for l in rendered.splitlines() if "Pick up dry cleaning" in l),
        "",
    )
    assert "2026-04-29" not in line


def test_render_three_buckets_in_correct_order():
    """When all three buckets have content, the prompt sees them in
    DUE TODAY → UPCOMING → OVERDUE order so the LLM leads with today."""
    from fabledassistant.services.journal_prep import _render_sections_for_prompt

    sections = {
        "tasks_due_today": [{"id": 1, "title": "Today task", "status": "todo", "priority": "none", "due_date": "2026-04-29"}],
        "tasks_upcoming": [{"id": 2, "title": "Upcoming task", "status": "todo", "priority": "none", "due_date": "2026-05-02"}],
        "tasks_overdue": [{"id": 3, "title": "Stale task", "status": "todo", "priority": "none", "due_date": "2026-02-20", "days_overdue": 68}],
    }
    rendered = _render_sections_for_prompt(sections)
    today_idx = rendered.index("TASKS DUE TODAY")
    upcoming_idx = rendered.index("UPCOMING TASKS")
    overdue_idx = rendered.index("OVERDUE TASKS")
    assert today_idx < upcoming_idx < overdue_idx
