"""ORCH-087: effort-in-stage-line (BR-EFF), honest done-time (BR-G5),
deterministic stage labels (G2) and deploy-cycle label (G3).

Telegram/Plane fully isolated (render is pure DB). Covers TC-06, TC-11..TC-15
and the confirm_deploy live-overlay label.
"""

import os
import tempfile

os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token")
os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token")

_test_db = os.path.join(tempfile.gettempdir(), "test_orchestrator_eff_time.db")
os.environ["ORCH_DB_PATH"] = _test_db

import pytest  # noqa: E402

import src.db as db_module  # noqa: E402
from src.db import init_db, get_db  # noqa: E402
from src import notifications as N  # noqa: E402


@pytest.fixture(autouse=True)
def setup_db(monkeypatch):
    monkeypatch.setattr(db_module.settings, "db_path", _test_db, raising=False)
    if os.path.exists(_test_db):
        os.unlink(_test_db)
    init_db()
    # No live overlay in render-only tests unless a test opts in.
    monkeypatch.setattr(N._get_settings(), "tracker_live_status", False, raising=False)
    yield
    if os.path.exists(_test_db):
        os.unlink(_test_db)


def _mk_task(stage="development", wid="ORCH-087", title="eff/time test",
             brd_start=None, brd_end=None, created=None, updated=None):
    conn = get_db()
    cur = conn.execute(
        "INSERT INTO tasks (plane_id, work_item_id, repo, branch, stage, title, "
        "brd_review_started_at, brd_review_ended_at) VALUES (?,?,?,?,?,?,?,?)",
        ("p1", wid, "orchestrator", "feature/ORCH-087-x", stage, title,
         brd_start, brd_end),
    )
    tid = cur.lastrowid
    if created or updated:
        conn.execute(
            "UPDATE tasks SET created_at=COALESCE(?, created_at), "
            "updated_at=COALESCE(?, updated_at) WHERE id=?",
            (created, updated, tid),
        )
    conn.commit()
    conn.close()
    return tid


def _mk_run(tid, agent, started, finished, *, effort=None, model="tokenator/claude-opus-4-8",
            in_tok=10, out_tok=5, cost=0.0, exit_code=0):
    conn = get_db()
    conn.execute(
        "INSERT INTO agent_runs (task_id, agent, started_at, finished_at, "
        "exit_code, input_tokens, output_tokens, cost_usd, model, effort) "
        "VALUES (?,?,?,?,?,?,?,?,?,?)",
        (tid, agent, started, finished, exit_code, in_tok, out_tok, cost, model, effort),
    )
    conn.commit()
    conn.close()


# --------------------------------------------------------------------------- #
# G2: plane_status_label deterministic for every stage (TC-06)
# --------------------------------------------------------------------------- #
def test_plane_status_label_all_stages():
    """TC-06/AC-2.2: every stage maps to its own label; deploy -> Awaiting Deploy."""
    cases = {
        "created": "To Analyse",
        "analysis": "Analysis",
        "architecture": "Architecture",
        "development": "Development",
        "review": "Code-Review",
        "testing": "Testing",
        "done": "Done",
    }
    for stage, expected in cases.items():
        assert N.plane_status_label({"stage": stage}) == expected
    deploy = N.plane_status_label({"stage": "deploy"})
    assert "Awaiting Deploy" in deploy
    # In Review derives from the brd-clock on the analysis stage.
    in_review = N.plane_status_label(
        {"stage": "analysis", "brd_review_started_at": "2026-06-04 10:00:00",
         "brd_review_ended_at": None}
    )
    assert "In Review" in in_review


def test_confirm_deploy_label_registered():
    """G3/AC-3.x: the deploy-cycle gains a confirm_deploy overlay label."""
    assert "confirm_deploy" in N._LIVE_BRANCH_LABELS
    assert "Confirm Deploy" in N._LIVE_BRANCH_LABELS["confirm_deploy"]
    # confirm_deploy is a REAL dedicated status -> no base-alias suppression.
    assert "confirm_deploy" not in N._LIVE_BRANCH_BASE


# --------------------------------------------------------------------------- #
# BR-EFF: effort rendered next to the model (TC-11, TC-12)
# --------------------------------------------------------------------------- #
@pytest.mark.parametrize("agent,label,effort", [
    ("developer", "Разработка", "xhigh"),
    ("tester", "Тестирование", "medium"),
    ("deployer", "Внедрение", "medium"),
    ("analyst", "Анализ", "high"),
    ("architect", "Архитектура", "high"),
    ("reviewer", "Код ревью", "high"),
])
def test_stage_line_shows_effort(agent, label, effort):
    """TC-11/AC-E.2,AC-E.3: stage line shows '· model · effort' for each role."""
    tid = _mk_task(stage="done")
    _mk_run(tid, agent, "2026-06-04 09:00:00", "2026-06-04 09:10:00", effort=effort)
    text = N.render_task_tracker(tid)
    line = [ln for ln in text.splitlines() if ln.startswith(f"✅ {label}")][0]
    assert line.rstrip().endswith(f"opus-4-8 · {effort}")


def test_stage_line_omits_empty_effort():
    """TC-12/AC-E.4: NULL effort -> suffix omitted, render does not crash."""
    tid = _mk_task(stage="analysis")
    _mk_run(tid, "analyst", "2026-06-04 09:00:00", "2026-06-04 09:10:00", effort=None)
    text = N.render_task_tracker(tid)
    line = [ln for ln in text.splitlines() if ln.startswith("✅ Анализ")][0]
    # Ends at the model (no trailing effort segment).
    assert line.rstrip().endswith("opus-4-8")


# --------------------------------------------------------------------------- #
# BR-G5: honest done-time (TC-13, TC-14, TC-15)
# --------------------------------------------------------------------------- #
def test_done_review_time_capped():
    """TC-13/AC-5.1: a ~6h open brd_review window is NOT shown as ~6h."""
    # 6h review window (10:00 -> 16:00) with default 2h cap.
    tid = _mk_task(
        stage="done",
        brd_start="2026-06-04 10:00:00", brd_end="2026-06-04 16:00:00",
        created="2026-06-04 09:00:00", updated="2026-06-04 16:30:00",
    )
    _mk_run(tid, "analyst", "2026-06-04 09:00:00", "2026-06-04 09:30:00", effort="high")
    text = N.render_task_tracker(tid)
    time_line = [ln for ln in text.splitlines() if ln.startswith("⏱")][0]
    # Capped to ~2h (120м), marked with '~'; the raw 360m is NOT shown as твоё.
    assert "твоё ~120м" in time_line
    assert "твоё 360м" not in time_line


def test_done_review_time_under_cap_uncapped():
    """AC-5.1: a normal short review window is shown verbatim (no '~')."""
    tid = _mk_task(
        stage="done",
        brd_start="2026-06-04 10:00:00", brd_end="2026-06-04 10:08:00",
        created="2026-06-04 09:00:00", updated="2026-06-04 10:30:00",
    )
    _mk_run(tid, "analyst", "2026-06-04 09:00:00", "2026-06-04 09:30:00", effort="high")
    text = N.render_task_tracker(tid)
    time_line = [ln for ln in text.splitlines() if ln.startswith("⏱")][0]
    assert "твоё 8м" in time_line
    assert "~" not in time_line


def test_done_time_line_labels_and_agent_sum():
    """TC-14,TC-15/AC-5.2,AC-5.3: agents=Σ runs; wall labelled 'общее с ожиданием'."""
    tid = _mk_task(
        stage="done",
        created="2026-06-04 09:00:00", updated="2026-06-04 11:00:00",  # wall 120m
    )
    # Two runs: 10m + 6m = 16m of agent time.
    _mk_run(tid, "analyst", "2026-06-04 09:00:00", "2026-06-04 09:10:00", effort="high")
    _mk_run(tid, "deployer", "2026-06-04 10:50:00", "2026-06-04 10:56:00", effort="medium")
    text = N.render_task_tracker(tid)
    time_line = [ln for ln in text.splitlines() if ln.startswith("⏱")][0]
    # agents = 16m (exact Σ), wall = 120m labelled as "общее с ожиданием".
    assert "Агенты 16м" in time_line          # Агенты 16м
    assert "общее с ожиданием 120м" in time_line  # общее с ожиданием 120м
    # wall (120m) != agents (16m) -> not presented as a sum.
    assert "Всего" not in time_line                      # no old "Всего"
