"""
tests/test_backlog_workflow.py — Workflow state machine tests.
"""
import os
import sys

import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "services", "router"))

from backlog_store import (
    MemoryBacklogStore, BacklogItem, BacklogEvent,
    validate_transition, _builtin_workflow, _new_id, _now_iso,
)


def _make_item(status: str = "open", **kw) -> BacklogItem:
    base = dict(
        id=_new_id("bl"), created_at=_now_iso(), updated_at=_now_iso(),
        env="prod", service="gateway", category="arch_review",
        title="Test item", description="", priority="P1",
        status=status, owner="oncall", due_date="2026-06-01",
        source="manual", dedupe_key=_new_id("dk"),
        evidence_refs={}, tags=[], meta={},
    )
    base.update(kw)
    return BacklogItem.from_dict(base)


WORKFLOW = _builtin_workflow()


class TestValidateTransition:
    def test_open_to_in_progress(self):
        assert validate_transition("open", "in_progress") is True

    def test_open_to_blocked(self):
        assert validate_transition("open", "blocked") is True

    def test_open_to_canceled(self):
        assert validate_transition("open", "canceled") is True

    def test_open_to_done_rejected(self):
        assert validate_transition("open", "done") is False

    def test_in_progress_to_done(self):
        assert validate_transition("in_progress", "done") is True

    def test_in_progress_to_blocked(self):
        assert validate_transition("in_progress", "blocked") is True

    def test_in_progress_to_canceled(self):
        assert validate_transition("in_progress", "canceled") is True

    def test_in_progress_to_open_rejected(self):
        assert validate_transition("in_progress", "open") is False

    def test_blocked_to_open(self):
        assert validate_transition("blocked", "open") is True

    def test_blocked_to_in_progress(self):
        assert validate_transition("blocked", "in_progress") is True

    def test_blocked_to_canceled(self):
        assert validate_transition("blocked", "canceled") is True

    def test_blocked_to_done_rejected(self):
        assert validate_transition("blocked", "done") is False

    def test_done_to_anything_rejected(self):
        for target in ("open", "in_progress", "blocked", "canceled"):
            assert validate_transition("done", target) is False

    def test_canceled_to_anything_rejected(self):
        for target in ("open", "in_progress", "blocked", "done"):
            assert validate_transition("canceled", target) is False


class TestWorkflowInStore:
    def _store(self):
        return MemoryBacklogStore()

    def test_set_status_valid_transition(self):
        store = self._store()
        item = _make_item(status="open")
        store.create(item)
        item.status = "in_progress"
        store.update(item)
        fetched = store.get(item.id)
        assert fetched.status == "in_progress"

    def test_set_status_records_event(self):
        store = self._store()
        item = _make_item(status="open")
        store.create(item)
        ev = BacklogEvent(
            id=_new_id("ev"), item_id=item.id, ts=_now_iso(),
            type="status_change", message="open → in_progress",
            actor="oncall", meta={"old_status": "open", "new_status": "in_progress"},
        )
        store.add_event(ev)
        events = store.get_events(item.id)
        assert any(e.type == "status_change" for e in events)

    def test_full_lifecycle_open_to_done(self):
        store = self._store()
        item = _make_item(status="open")
        store.create(item)
        for new_status in ("in_progress", "done"):
            assert validate_transition(item.status, new_status) is True
            item.status = new_status
            store.update(item)
        fetched = store.get(item.id)
        assert fetched.status == "done"

    def test_done_item_cannot_reopen(self):
        item = _make_item(status="done")
        assert validate_transition(item.status, "open") is False
        assert validate_transition(item.status, "in_progress") is False

    def test_canceled_item_is_terminal(self):
        item = _make_item(status="canceled")
        for t in ("open", "in_progress", "blocked", "done"):
            assert validate_transition(item.status, t) is False

    def test_policy_overrides_builtin(self):
        custom_policy = {
            "workflow": {
                "allowed_transitions": {
                    "open": ["done"],  # Only allow direct done (custom)
                }
            }
        }
        assert validate_transition("open", "done", custom_policy) is True
        assert validate_transition("open", "in_progress", custom_policy) is False


class TestCommentEvents:
    def test_add_comment_creates_event(self):
        store = MemoryBacklogStore()
        item = _make_item()
        store.create(item)
        ev = BacklogEvent(
            id=_new_id("ev"), item_id=item.id, ts=_now_iso(),
            type="comment", message="Investigated — deprioritizing", actor="cto",
        )
        store.add_event(ev)
        events = store.get_events(item.id)
        comments = [e for e in events if e.type == "comment"]
        assert len(comments) == 1
        assert "Investigated" in comments[0].message

    def test_multiple_events_preserved_in_order(self):
        store = MemoryBacklogStore()
        item = _make_item()
        store.create(item)
        for i in range(5):
            store.add_event(BacklogEvent(
                id=_new_id("ev"), item_id=item.id, ts=_now_iso(),
                type="comment", message=f"Comment {i}", actor="agent",
            ))
        events = store.get_events(item.id, limit=10)
        assert len(events) == 5

    def test_auto_update_event_type(self):
        store = MemoryBacklogStore()
        item = _make_item()
        store.create(item)
        ev = BacklogEvent(
            id=_new_id("ev"), item_id=item.id, ts=_now_iso(),
            type="auto_update", message="Updated by weekly digest", actor="backlog_generator",
        )
        store.add_event(ev)
        events = store.get_events(item.id)
        assert any(e.type == "auto_update" for e in events)
