"""ORCH-019 — advance_stage routing-override (ADR-001 D3).

Covers (04-test-plan.yaml):
  TC-05  bug task: analysis -> development (architecture skipped, developer
         enqueued); non-bug task: analysis -> architecture (architect enqueued).
  TC-06  STAGE_TRANSITIONS is structurally unchanged (set of stages + edges +
         agents + qg byte-for-byte) — the override does NOT mutate the table.
"""
import os
import tempfile

import pytest

_test_db = os.path.join(tempfile.gettempdir(), "test_bug_fast_track_routing.db")
os.environ["ORCH_DB_PATH"] = _test_db
os.environ["ORCH_REPOS_DIR"] = tempfile.gettempdir()
os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token")
os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token")

import src.db as db  # noqa: E402
from src.db import init_db, get_db, set_task_track  # noqa: E402
from src import stage_engine  # noqa: E402
from src import config as cfg  # noqa: E402
from src.stage_engine import advance_stage  # noqa: E402


@pytest.fixture(autouse=True)
def fresh_db(monkeypatch, tmp_path):
    dbfile = tmp_path / "r.db"
    monkeypatch.setattr(db.settings, "db_path", str(dbfile))
    monkeypatch.setattr(cfg.settings, "bug_fast_track_enabled", True, raising=False)
    init_db()
    yield


@pytest.fixture(autouse=True)
def silence_side_effects(monkeypatch):
    for name in (
        "notify_stage_change", "notify_qg_failure", "notify_approve_requested",
        "send_telegram", "plane_notify_stage", "plane_notify_qg", "plane_add_comment",
        "set_issue_in_review", "set_issue_needs_input", "set_issue_in_progress",
        "set_issue_blocked", "set_issue_done", "set_issue_analysis",
        "set_issue_awaiting_deploy", "set_issue_deploying", "set_issue_monitoring",
        "set_issue_approved",
    ):
        monkeypatch.setattr(stage_engine, name, lambda *a, **k: None, raising=False)
    yield


def _make_task(work_item_id, stage="analysis", repo="orchestrator"):
    conn = get_db()
    cur = conn.execute(
        "INSERT INTO tasks (plane_id, work_item_id, repo, branch, stage, title) "
        "VALUES (?, ?, ?, ?, ?, ?)",
        (work_item_id, work_item_id, repo, f"feature/{work_item_id}", stage, work_item_id),
    )
    tid = cur.lastrowid
    conn.commit()
    conn.close()
    return tid


# --- TC-05 -----------------------------------------------------------------
def test_tc05_bug_task_skips_architecture():
    tid = _make_task("ORCH-bug", stage="analysis")
    set_task_track(tid, "bug")
    # agent=None -> the webhook Approved-via-status path (gate satisfied, advance).
    res = advance_stage(
        tid, "analysis", "orchestrator", "ORCH-bug", "feature/ORCH-bug",
        finished_agent=None,
    )
    assert res.advanced is True
    assert res.to_stage == "development"
    assert res.enqueued_agent == "developer"
    # DB stage actually advanced past architecture.
    row = db.get_task_by_work_item_id("ORCH-bug")
    assert row["stage"] == "development"


def test_tc05_full_task_keeps_architecture():
    tid = _make_task("ORCH-full", stage="analysis")
    # track defaults to 'full' (no set_task_track call).
    res = advance_stage(
        tid, "analysis", "orchestrator", "ORCH-full", "feature/ORCH-full",
        finished_agent=None,
    )
    assert res.advanced is True
    assert res.to_stage == "architecture"
    assert res.enqueued_agent == "architect"


def test_tc05_killswitch_off_bug_keeps_architecture(monkeypatch):
    monkeypatch.setattr(cfg.settings, "bug_fast_track_enabled", False, raising=False)
    tid = _make_task("ORCH-bugoff", stage="analysis")
    set_task_track(tid, "bug")  # stored, but the flag is off -> inert
    res = advance_stage(
        tid, "analysis", "orchestrator", "ORCH-bugoff", "feature/ORCH-bugoff",
        finished_agent=None,
    )
    assert res.to_stage == "architecture"
    assert res.enqueued_agent == "architect"


def test_tc05_bug_only_affects_analysis_edge():
    """The override is scoped to the analysis-exit edge only — a bug task on
    `development` still routes development -> review (no spurious skips)."""
    tid = _make_task("ORCH-bugdev", stage="development")
    set_task_track(tid, "bug")
    # Make check_ci_green pass deterministically (we only assert routing, not CI).
    import src.stage_engine as se
    orig = se.QG_CHECKS.get("check_ci_green")
    se.QG_CHECKS["check_ci_green"] = lambda *a, **k: (True, "ok")
    try:
        res = advance_stage(
            tid, "development", "orchestrator", "ORCH-bugdev", "feature/ORCH-bugdev",
            finished_agent=None,
        )
    finally:
        if orig is not None:
            se.QG_CHECKS["check_ci_green"] = orig
    assert res.to_stage == "review"


# --- TC-06: STAGE_TRANSITIONS structurally unchanged -----------------------
def test_tc06_stage_transitions_unchanged():
    from src.stages import STAGE_TRANSITIONS
    expected = {
        "created": {"next": "analysis", "agent": "analyst", "qg": None},
        "analysis": {"next": "architecture", "agent": "architect", "qg": "check_analysis_approved"},
        "architecture": {"next": "development", "agent": "developer", "qg": "check_architecture_done"},
        "development": {"next": "review", "agent": "reviewer", "qg": "check_ci_green"},
        "review": {"next": "testing", "agent": "tester", "qg": "check_reviewer_verdict"},
        "testing": {"next": "deploy-staging", "agent": "deployer", "qg": "check_tests_passed"},
        "deploy-staging": {"next": "deploy", "agent": "deployer", "qg": "check_staging_status"},
        "deploy": {"next": "done", "agent": None, "qg": "check_deploy_status"},
        "done": {"next": None, "agent": None, "qg": None},
        "cancelled": {"next": None, "agent": None, "qg": None},
    }
    assert STAGE_TRANSITIONS == expected


def test_tc06_get_next_stage_pure():
    """get_next_stage / get_agent_for_stage stay PURE (no track arg) — the override
    lives in advance_stage, not in stages.py."""
    from src.stages import get_next_stage, get_agent_for_stage
    assert get_next_stage("analysis") == "architecture"
    assert get_agent_for_stage("analysis") == "architect"
