"""ORCH-016 / TC-01..TC-10, TC-12, TC-23: unified status comment format.

Unit tests for src.usage.build_status_comment(...) — the single hot path for
every agent's "I just finished a stage" comment in Plane (ADR-001).

Covers:
  * Header per agent (icon + role + description from AC-1..AC-5).
  * Verdict / Status line read from frontmatter (reviewer / tester / deployer).
  * Длительность line shown when duration_s is supplied; suppressed otherwise.
  * <a href="..."> link items per agent.
  * URL base picks gitea_public_url, falls back to gitea_url.
  * Graceful behaviour when files are missing / no frontmatter (AC-8).

No DB / no network — only the worktree filesystem (via tmp_path).
"""

import os

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

import pytest  # noqa: E402

from src import usage as U  # noqa: E402


WID = "ET-016"
REPO = "enduro-trails"
BRANCH = "feature/ET-016-status-comments"


@pytest.fixture(autouse=True)
def _set_urls(monkeypatch):
    """gitea_public_url is the canonical clickable base (AC-9)."""
    monkeypatch.setattr(U, "logger", U.logger)
    from src.config import settings
    monkeypatch.setattr(settings, "gitea_url", "http://localhost:3000", raising=False)
    monkeypatch.setattr(
        settings, "gitea_public_url", "https://git.mva154.duckdns.org", raising=False
    )
    monkeypatch.setattr(settings, "gitea_owner", "admin", raising=False)
    yield


def _wt_with_files(tmp_path, files: dict) -> str:
    """Create a worktree skeleton with given files. `files` maps rel-path -> body."""
    base = tmp_path / "wt"
    docs = base / "docs" / "work-items" / WID
    docs.mkdir(parents=True)
    for rel, body in files.items():
        p = docs / rel if not rel.startswith("/") else base / rel.lstrip("/")
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(body)
    return str(base)


# ---------------------------------------------------------------------------
# TC-01: architect comment
# ---------------------------------------------------------------------------
def test_tc01_architect_comment(tmp_path):
    wt = _wt_with_files(tmp_path, {"06-adr/ADR-001-x.md": "x"})

    html = U.build_status_comment(
        "architect",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=312,
        worktree_root=wt,
    )
    # Header
    assert "\U0001f4d0 Architect — " in html, html
    assert "архитектурную" in html
    assert "См. ADR ниже" in html
    # Duration: 312s -> 5m 12s
    assert "Длительность: 5m 12s" in html
    # ADR link via gitea_public_url
    assert ("https://git.mva154.duckdns.org/admin/enduro-trails/src/branch/"
            f"{BRANCH}/docs/work-items/{WID}/06-adr") in html
    # No Verdict for architect
    assert "Verdict" not in html
    assert "Status:" not in html


# ---------------------------------------------------------------------------
# TC-02: developer comment with PR + branch
# ---------------------------------------------------------------------------
def test_tc02_developer_comment_links_branch_and_pr():
    html = U.build_status_comment(
        "developer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        pr_number=42, duration_s=600,
    )
    assert "\U0001f4bb Developer — " in html
    assert "разработку" in html
    # Both branch and PR links
    assert f"https://git.mva154.duckdns.org/admin/{REPO}/src/branch/{BRANCH}" in html
    assert f"https://git.mva154.duckdns.org/admin/{REPO}/pulls/42" in html
    assert f"PR #42" in html
    assert "Длительность: 10m 00s" in html
    assert "Verdict" not in html


# ---------------------------------------------------------------------------
# TC-03 / TC-04: reviewer verdict via frontmatter
# ---------------------------------------------------------------------------
def test_tc03_reviewer_verdict_approve(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "12-review.md": "---\nverdict: APPROVE\n---\nbody...",
    })
    html = U.build_status_comment(
        "reviewer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=120, worktree_root=wt,
    )
    assert "\U0001f50e Reviewer — " in html
    assert "Verdict: APPROVE" in html
    assert "Длительность: 2m 00s" in html
    assert "12-review.md" in html


def test_tc04_reviewer_verdict_request_changes(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "12-review.md": "---\nverdict: REQUEST_CHANGES\n---\nblockers...",
    })
    html = U.build_status_comment(
        "reviewer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=45, worktree_root=wt,
    )
    assert "Verdict: REQUEST_CHANGES" in html
    assert "Длительность: 45s" in html


# ---------------------------------------------------------------------------
# TC-05: reviewer with NO 12-review.md -> graceful (no Verdict, no Review link)
# but Длительность and header still present.
# ---------------------------------------------------------------------------
def test_tc05_reviewer_missing_artifact_graceful(tmp_path):
    wt = _wt_with_files(tmp_path, {})  # empty docs dir
    html = U.build_status_comment(
        "reviewer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=30, worktree_root=wt,
    )
    assert "\U0001f50e Reviewer — " in html
    assert "Verdict" not in html
    # Link to 12-review.md is dropped (AC-8 graceful).
    assert "12-review.md" not in html
    # Duration still printed when known.
    assert "Длительность: 30s" in html


# ---------------------------------------------------------------------------
# TC-06 / TC-07: tester verdict via frontmatter (verdict OR status)
# ---------------------------------------------------------------------------
def test_tc06_tester_pass(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "13-test-report.md": "---\nverdict: PASS\n---\n",
    })
    html = U.build_status_comment(
        "tester",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=240, worktree_root=wt,
    )
    assert "\U0001f9ea Tester — " in html
    assert "Verdict: PASS" in html
    assert "Длительность: 4m 00s" in html
    assert "13-test-report.md" in html


def test_tc07_tester_fail(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "13-test-report.md": "---\nverdict: FAIL\n---\n",
    })
    html = U.build_status_comment(
        "tester",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=240, worktree_root=wt,
    )
    assert "Verdict: FAIL" in html
    assert "Длительность: 4m 00s" in html


def test_tc07b_tester_falls_back_to_status_key(tmp_path):
    # Some testers used `status:` instead of `verdict:` (ET-006 / ET-008 pattern).
    wt = _wt_with_files(tmp_path, {
        "13-test-report.md": "---\nstatus: PASSED\n---\n",
    })
    html = U.build_status_comment(
        "tester",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=10, worktree_root=wt,
    )
    assert "Verdict: PASSED" in html


# ---------------------------------------------------------------------------
# TC-08 / TC-09: deployer status via frontmatter
# ---------------------------------------------------------------------------
def test_tc08_deployer_deploy_status_success(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "14-deploy-log.md": "---\ndeploy_status: SUCCESS\n---\n",
    })
    html = U.build_status_comment(
        "deployer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        stage="deploy", duration_s=120, worktree_root=wt,
    )
    assert "\U0001f680 Deployer — " in html
    assert "Status: SUCCESS" in html
    assert "Длительность: 2m 00s" in html
    assert "14-deploy-log.md" in html


def test_tc09_deployer_staging_status_success(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "15-staging-log.md": "---\nstaging_status: SUCCESS\n---\n",
    })
    html = U.build_status_comment(
        "deployer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        stage="deploy-staging", duration_s=60, worktree_root=wt,
    )
    assert "Status: SUCCESS" in html
    assert "Длительность: 1m 00s" in html
    # The staging-stage helper links 15-staging-log.md, not 14-deploy-log.md.
    assert "15-staging-log.md" in html
    assert "14-deploy-log.md" not in html


def test_deployer_status_failed_drives_status_line(tmp_path):
    wt = _wt_with_files(tmp_path, {
        "14-deploy-log.md": "---\ndeploy_status: FAILED\n---\n",
    })
    html = U.build_status_comment(
        "deployer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        stage="deploy", duration_s=5, worktree_root=wt,
    )
    assert "Status: FAILED" in html


# ---------------------------------------------------------------------------
# TC-10: gitea_public_url is preferred; falls back to gitea_url when empty.
# ---------------------------------------------------------------------------
def test_tc10_url_fallback_to_gitea_url(monkeypatch):
    from src.config import settings
    monkeypatch.setattr(settings, "gitea_public_url", "", raising=False)
    monkeypatch.setattr(settings, "gitea_url", "http://localhost:3000", raising=False)
    html = U.build_status_comment(
        "developer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        pr_number=7, duration_s=15,
    )
    assert "http://localhost:3000/admin/enduro-trails/pulls/7" in html
    # And the public URL is not there because it was empty.
    assert "git.mva154.duckdns.org" not in html


# ---------------------------------------------------------------------------
# TC-12: frontmatter parser is graceful — missing file / empty / bad YAML -> None
# (the comment still publishes the header + duration, just no Verdict / Status).
# ---------------------------------------------------------------------------
def test_tc12_frontmatter_missing_file_no_crash(tmp_path):
    from src.frontmatter import read_frontmatter_value
    assert read_frontmatter_value(str(tmp_path / "nope.md"), "verdict") is None


def test_tc12_frontmatter_empty_no_crash(tmp_path):
    p = tmp_path / "empty.md"
    p.write_text("")
    from src.frontmatter import read_frontmatter_value
    assert read_frontmatter_value(str(p), "verdict") is None


def test_tc12_frontmatter_bad_yaml_no_crash(tmp_path):
    p = tmp_path / "bad.md"
    p.write_text("---\nverdict: [unterminated\n---\nbody")
    from src.frontmatter import read_frontmatter_value
    assert read_frontmatter_value(str(p), "verdict") is None


def test_tc12_frontmatter_missing_key_returns_none(tmp_path):
    p = tmp_path / "ok.md"
    p.write_text("---\nother: value\n---\nbody")
    from src.frontmatter import read_frontmatter_value
    assert read_frontmatter_value(str(p), "verdict") is None


# ---------------------------------------------------------------------------
# TC-23: duration_s=None and no task_id -> the Длительность line is OMITTED.
# Header / description / artifact links remain.
# ---------------------------------------------------------------------------
def test_tc23_no_duration_no_line(tmp_path):
    wt = _wt_with_files(tmp_path, {"06-adr/ADR-001-x.md": "x"})
    html_none = U.build_status_comment(
        "architect",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        duration_s=None, worktree_root=wt,
    )
    html_default = U.build_status_comment(
        "architect",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        worktree_root=wt,
    )
    for html in (html_none, html_default):
        assert "Длительность" not in html
        # But the header, description and ADR link are still there.
        assert "\U0001f4d0 Architect — " in html
        assert "архитектурную" in html
        assert "06-adr" in html


# ---------------------------------------------------------------------------
# Extra: usage tail is rendered as <sub> when non-zero, suppressed otherwise.
# (Backs up ADR-001 §3 and keeps the old usage_comment test contract.)
# ---------------------------------------------------------------------------
def test_usage_tail_rendered_when_non_zero():
    html = U.build_status_comment(
        "developer",
        repo=REPO, branch=BRANCH, work_item_id=WID,
        usage={"input_tokens": 45231, "output_tokens": 12100, "cost_usd": 0.21},
    )
    assert "<sub>" in html and "</sub>" in html
    assert "45.2k in" in html
    assert "12.1k out" in html
    assert "$0.21" in html


def test_usage_tail_suppressed_when_all_zero():
    html = U.build_status_comment("developer", repo=REPO, branch=BRANCH)
    assert "<sub>" not in html


# ---------------------------------------------------------------------------
# AC-1 / AC-5 literal strings — fixed wording per role.
# ---------------------------------------------------------------------------
def test_ac1_architect_header_literal():
    html = U.build_status_comment("architect", repo=REPO, branch=BRANCH,
                                  work_item_id=WID, duration_s=10)
    assert "\U0001f4d0 Architect — " in html


def test_ac5_deployer_deploy_description():
    html = U.build_status_comment(
        "deployer", repo=REPO, branch=BRANCH, work_item_id=WID, stage="deploy",
    )
    assert "прод-деплой" in html


def test_ac5_deployer_staging_description():
    html = U.build_status_comment(
        "deployer", repo=REPO, branch=BRANCH, work_item_id=WID, stage="deploy-staging",
    )
    assert "staging-деплой" in html
