"""Opt-in integration tests against a real (containerized) Gitea (#66).

Skipped by default. Enable with GITEA_INTEGRATION=1 plus a local instance and
token — see tests/integration/README.md. These prove real Gitea behavior that
the mocked unit suite can only simulate: pagination, targeted label edits,
permission fail-closed, and error payload surfacing — all through the shared
client (``gitea_auth.api_request`` / ``api_get_all``, #65/#67 shape).

No production credentials; tokens never appear in output or assertions.
"""
import os
import sys
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))

from gitea_auth import api_request, api_get_all  # noqa: E402

pytestmark = pytest.mark.skipif(
    os.environ.get("GITEA_INTEGRATION") != "1",
    reason="integration tests are opt-in: set GITEA_INTEGRATION=1 (see tests/integration/README.md)",
)


# --- issue listing + pagination --------------------------------------------

N_ISSUES = 7  # > page_size below, forcing a real multi-page walk


@pytest.fixture(scope="module")
def issues(gitea, seed_repo):
    created = []
    for i in range(N_ISSUES):
        created.append(api_request(
            "POST", f"{seed_repo['api']}/issues", gitea["auth"],
            payload={"title": f"pagination seed {i}"}))
    return created


def test_issue_pagination_walks_all_pages(gitea, seed_repo, issues):
    got = api_get_all(f"{seed_repo['api']}/issues?state=open", gitea["auth"],
                      page_size=3)
    titles = {i["title"] for i in got}
    assert {f"pagination seed {i}" for i in range(N_ISSUES)} <= titles
    assert len(got) >= N_ISSUES


def test_issue_pagination_honors_overall_limit(gitea, seed_repo, issues):
    got = api_get_all(f"{seed_repo['api']}/issues?state=open", gitea["auth"],
                      page_size=3, limit=4)
    assert len(got) == 4


# --- PR listing --------------------------------------------------------------

def test_pr_listing_via_shared_client(gitea, seed_repo, issues):
    # Create a branch (via the contents API) and a real PR, then list.
    api_request(
        "POST", f"{seed_repo['api']}/contents/inttest.txt", gitea["auth"],
        payload={"content": "aW50ZWdyYXRpb24gc2VlZAo=",  # "integration seed"
                 "message": "seed PR branch", "new_branch": "inttest-pr"})
    pr = api_request(
        "POST", f"{seed_repo['api']}/pulls", gitea["auth"],
        payload={"title": "integration seed PR", "head": "inttest-pr",
                 "base": "main"})
    got = api_get_all(f"{seed_repo['api']}/pulls?state=open", gitea["auth"],
                      page_size=1)
    assert any(p["number"] == pr["number"] for p in got)


# --- targeted label add/remove ----------------------------------------------

def test_targeted_label_add_and_remove(gitea, seed_repo, issues):
    labels = {}
    for name, color in (("keep-me", "#00ff00"), ("drop-me", "#ff0000")):
        labels[name] = api_request(
            "POST", f"{seed_repo['api']}/labels", gitea["auth"],
            payload={"name": name, "color": color})
    issue_no = issues[0]["number"]
    issue_labels_url = f"{seed_repo['api']}/issues/{issue_no}/labels"
    api_request("POST", issue_labels_url, gitea["auth"],
                payload={"labels": [labels["keep-me"]["id"],
                                    labels["drop-me"]["id"]]})
    # Targeted removal of one label must not disturb the other.
    api_request("DELETE", f"{issue_labels_url}/{labels['drop-me']['id']}",
                gitea["auth"])
    remaining = {l["name"] for l in api_request("GET", issue_labels_url,
                                                gitea["auth"])}
    assert "keep-me" in remaining
    assert "drop-me" not in remaining


# --- permission denial / fail-closed -----------------------------------------

def test_bad_token_fails_closed_without_leaking_it(gitea):
    bogus = "token 0123456789abcdef0123456789abcdef01234567"
    with pytest.raises(RuntimeError) as exc:
        api_request("GET", f"{gitea['base']}/api/v1/user", bogus)
    msg = str(exc.value)
    assert "401" in msg
    assert "0123456789abcdef" not in msg  # credential never echoed


def test_real_error_payload_surfaces_safely(gitea, seed_repo):
    # A genuinely missing resource: Gitea's real 404 error payload must become
    # a clear RuntimeError, not a stack trace, and must not echo the token.
    with pytest.raises(RuntimeError) as exc:
        api_request("GET", f"{seed_repo['api']}/issues/999999", gitea["auth"])
    msg = str(exc.value)
    assert "404" in msg
    token = os.environ.get("GITEA_INTEGRATION_TOKEN", "")
    if token:
        assert token not in msg
