"""The running list: merging the items file with rian's recorded state (app/services/items.py)."""

from datetime import date, datetime, timezone

from app.services import items as svc

TODAY = date(2026, 9, 10)


def item(id: str, kind: str = "issue", **kw) -> dict:
    base = {"id": id, "kind": kind, "title": id, "detail": "", "owner": None, "priority": None, "options": [],
            "assumption": None, "links": [], "due": None, "created": "2026-09-05", "by": "test"}
    base.update(kw)
    return base


class TestMerge:
    def test_open_when_nothing_recorded(self):
        (m,) = svc.merge([item("a")], {}, TODAY)
        assert m["status"] == "open" and m["visible"] is True and m["thread_key"] == "item:a"

    def test_page_state_wins_over_file(self):
        states = {"a": {"status": "done", "decision": "yes", "acted_by": "rian", "acted_at": datetime(2026, 9, 9, tzinfo=timezone.utc)}}
        (m,) = svc.merge([item("a", resolved={"by": "Stream A", "on": "2026-09-01", "note": "x"})], states, TODAY)
        assert m["status"] == "done" and m["decision"] == "yes" and m["closed_on"] == "2026-09-09"

    def test_session_resolution_closes_and_ages_out(self):
        fresh = item("a", resolved={"by": "Stream A", "on": "2026-09-05", "note": "fixed"})
        stale = item("b", resolved={"by": "Stream A", "on": "2026-08-20", "note": "fixed"})
        a, b = svc.merge([fresh, stale], {}, TODAY)
        assert a["status"] == "resolved" and a["visible"] is True
        assert b["status"] == "resolved" and b["visible"] is False

    def test_reopened_on_page_is_open_again(self):
        states = {"a": {"status": "open", "decision": None, "acted_by": "rian", "acted_at": datetime(2026, 9, 9, tzinfo=timezone.utc)}}
        (m,) = svc.merge([item("a", resolved={"by": "Stream A", "on": "2026-09-05", "note": ""})], states, TODAY)
        assert m["status"] == "open" and m["closed_on"] is None

    def test_order_is_urgency_then_date_then_kind_then_priority(self):
        rows = [item("p3", priority="P3"), item("p1", priority="P1"), item("do-late", kind="do", due="2026-09-12"),
                item("do-soon", kind="do", due="2026-09-06"), item("dec", kind="decide")]
        # do-soon's own date has arrived (now); the rest are "later", ordered by date, then kind, then priority.
        assert [m["id"] for m in svc.merge(rows, {}, TODAY)] == ["do-soon", "do-late", "dec", "p1", "p3"]

    def test_counts_open_by_kind_and_visible_closed(self):
        rows = [item("a", kind="decide"), item("b"), item("c", resolved={"by": "x", "on": "2026-09-09", "note": ""})]
        c = svc.counts(svc.merge(rows, {}, TODAY))
        assert {k: c[k] for k in ("decide", "do", "issue", "closed")} == {"decide": 1, "do": 0, "issue": 1, "closed": 1}
        assert c["later"] == 2 and c["now"] == 0


class TestUrgency:
    PLAN = {
        "R4": {"id": "R4", "title": "Singapore collector", "status": "doing", "due": "2026-09-09"},
        "A13": {"id": "A13", "title": "Switch the nineteen on", "status": "todo", "due": "2026-09-11"},
        "B6": {"id": "B6", "title": "Category pages", "status": "todo", "due": "2026-09-15"},
        "Q3": {"id": "Q3", "title": "verify", "status": "done", "due": "2026-09-09"},
    }

    def test_gated_task_in_progress_is_now(self):
        (m,) = svc.merge([item("a", kind="decide", blocks=["R4"], weight="blocking")], {}, TODAY, self.PLAN)
        assert m["urgency"] == "now" and "R4" in m["reason"]

    def test_gated_task_due_within_window_is_now(self):
        (m,) = svc.merge([item("a", kind="decide", blocks=["A13"], weight="costly")], {}, TODAY, self.PLAN)
        assert m["urgency"] == "now"

    def test_gated_task_far_out_is_soon_with_its_date(self):
        (m,) = svc.merge([item("a", kind="decide", blocks=["B6"], weight="blocking")], {}, date(2026, 9, 6), self.PLAN)
        assert m["urgency"] == "soon" and "B6" in m["reason"] and m["gates"][0]["due"] == "2026-09-15"

    def test_all_gates_done_is_overtaken(self):
        (m,) = svc.merge([item("a", kind="decide", blocks=["Q3"], weight="costly")], {}, TODAY, self.PLAN)
        assert m["urgency"] == "overtaken"

    def test_no_gate_weights(self):
        a, b = svc.merge([item("a", kind="issue", weight="costly"), item("b", kind="issue", weight="info")], {}, TODAY, {})
        assert (a["urgency"], b["urgency"]) == ("soon", "later")

    def test_do_item_own_date_arrived_is_now(self):
        (m,) = svc.merge([item("a", kind="do", due="2026-09-10", weight="info")], {}, TODAY, {})
        assert m["urgency"] == "now"

    def test_now_sorts_before_soon_and_later_regardless_of_kind(self):
        rows = [item("later-decide", kind="decide", weight="info"), item("soon-issue", blocks=["B6"], weight="costly"), item("now-issue", blocks=["R4"], weight="blocking")]
        assert [m["id"] for m in svc.merge(rows, {}, date(2026, 9, 6), self.PLAN)] == ["now-issue", "soon-issue", "later-decide"]

    def test_closed_items_carry_no_urgency(self):
        (m,) = svc.merge([item("a", blocks=["R4"], resolved={"by": "x", "on": "2026-09-09", "note": ""})], {}, TODAY, self.PLAN)
        assert m["urgency"] is None and m["reason"] is None
