"""Tests for PIM context middleware counts.

Regression tests for:
- _count_open_todos excludes COMPLETED and CANCELLED todos
- _count_events counts all .ics files (honest label, no false "next 7 days")
- _build_section renders accurate labels in the template
"""

from __future__ import annotations

from pathlib import Path

import pytest
from icarus.pim.todos import create_todo
from icarus.runtime.pim_context import (
    PIMContextMiddleware,
    _count_events,
    _count_open_todos,
)

# ── _count_open_todos ──────────────────────────────────────────


class TestCountOpenTodos:
    """_count_open_todos must exclude COMPLETED and CANCELLED todos."""

    @pytest.fixture()
    def todos_dir(self, tmp_path: Path) -> Path:
        d = tmp_path / "todos"
        d.mkdir()
        return d

    def test_empty_dir(self, todos_dir: Path):
        assert _count_open_todos(todos_dir) == 0

    def test_missing_dir(self, tmp_path: Path):
        assert _count_open_todos(tmp_path / "nonexistent") == 0

    def test_counts_needs_action(self, todos_dir: Path):
        create_todo(todos_dir, {"summary": "Open task", "uid": "t1"})
        assert _count_open_todos(todos_dir) == 1

    def test_counts_in_process(self, todos_dir: Path):
        create_todo(todos_dir, {"summary": "In progress", "uid": "t2", "status": "IN-PROCESS"})
        assert _count_open_todos(todos_dir) == 1

    def test_excludes_completed(self, todos_dir: Path):
        create_todo(todos_dir, {"summary": "Done", "uid": "t3", "status": "COMPLETED"})
        assert _count_open_todos(todos_dir) == 0

    def test_excludes_cancelled(self, todos_dir: Path):
        create_todo(todos_dir, {"summary": "Nope", "uid": "t4", "status": "CANCELLED"})
        assert _count_open_todos(todos_dir) == 0

    def test_mixed_statuses(self, todos_dir: Path):
        """3 open + 2 closed = count should be 3."""
        create_todo(todos_dir, {"summary": "Open 1", "uid": "a1"})
        create_todo(todos_dir, {"summary": "Open 2", "uid": "a2"})
        create_todo(todos_dir, {"summary": "WIP", "uid": "a3", "status": "IN-PROCESS"})
        create_todo(todos_dir, {"summary": "Done", "uid": "a4", "status": "COMPLETED"})
        create_todo(todos_dir, {"summary": "Cancelled", "uid": "a5", "status": "CANCELLED"})
        assert _count_open_todos(todos_dir) == 3

    def test_unreadable_file_skipped(self, todos_dir: Path):
        """Files that raise OSError on read are silently skipped."""
        create_todo(todos_dir, {"summary": "Good", "uid": "g1"})
        # Create a broken .ics (directory masquerading as file won't read)
        bad = todos_dir / "bad.ics"
        bad.mkdir()  # directory, not file — read_bytes() will raise
        assert _count_open_todos(todos_dir) == 1


# ── _count_events ──────────────────────────────────────────────


class TestCountEvents:
    """_count_events counts all .ics files — no date filtering."""

    def test_empty_dir(self, tmp_path: Path):
        cal_dir = tmp_path / "calendar"
        cal_dir.mkdir()
        assert _count_events(cal_dir) == 0

    def test_missing_dir(self, tmp_path: Path):
        assert _count_events(tmp_path / "nonexistent") == 0

    def test_counts_all_ics_files(self, tmp_path: Path):
        cal_dir = tmp_path / "calendar"
        cal_dir.mkdir()
        for i in range(5):
            (cal_dir / f"event-{i}.ics").write_text("placeholder")
        assert _count_events(cal_dir) == 5

    def test_ignores_non_ics(self, tmp_path: Path):
        cal_dir = tmp_path / "calendar"
        cal_dir.mkdir()
        (cal_dir / "event.ics").write_text("placeholder")
        (cal_dir / "notes.txt").write_text("not an event")
        assert _count_events(cal_dir) == 1


# ── Template integration ───────────────────────────────────────


class TestBuildSection:
    """_build_section renders correct labels with live counts from state."""

    @pytest.fixture()
    def pim_dirs(self, tmp_path: Path) -> tuple[Path, Path, Path]:
        contacts = tmp_path / "contacts"
        calendar = tmp_path / "calendar"
        todos = tmp_path / "todos"
        contacts.mkdir()
        calendar.mkdir()
        todos.mkdir()
        return contacts, calendar, todos

    def _get_state(self, mw: PIMContextMiddleware) -> dict:
        """Run before_agent to populate state, mimicking the real lifecycle."""
        from unittest.mock import MagicMock

        return mw.before_agent({}, MagicMock())

    def test_template_says_calendar_events_not_next_7_days(self, pim_dirs):
        contacts, calendar, todos = pim_dirs
        mw = PIMContextMiddleware(contacts, calendar, todos)
        state = self._get_state(mw)
        section = mw._build_section(state)
        # Must say "calendar events", not "events next 7 days"
        assert "calendar events" in section
        assert "next 7 days" not in section

    def test_template_says_open_tasks(self, pim_dirs):
        contacts, calendar, todos = pim_dirs
        mw = PIMContextMiddleware(contacts, calendar, todos)
        state = self._get_state(mw)
        section = mw._build_section(state)
        assert "open tasks" in section

    def test_open_todo_count_accurate(self, pim_dirs):
        contacts, calendar, todos = pim_dirs
        create_todo(todos, {"summary": "A", "uid": "x1"})
        create_todo(todos, {"summary": "B", "uid": "x2", "status": "COMPLETED"})
        mw = PIMContextMiddleware(contacts, calendar, todos)
        state = self._get_state(mw)
        section = mw._build_section(state)
        # Only 1 open, not 2
        assert "1 open tasks" in section

    def test_event_count_all_files(self, pim_dirs):
        contacts, calendar, todos = pim_dirs
        for i in range(3):
            (calendar / f"e{i}.ics").write_text("placeholder")
        mw = PIMContextMiddleware(contacts, calendar, todos)
        state = self._get_state(mw)
        section = mw._build_section(state)
        assert "3 calendar events" in section
