# retoor <retoor@molodetz.nl>

from datetime import datetime, timezone

import pytest
from fastapi.testclient import TestClient

from devplacepy.main import app
from devplacepy.database import (
    get_table,
    get_primary_admin_uid,
    invalidate_admins_cache,
    refresh_snapshot,
    set_setting,
)
from devplacepy.utils import generate_uid, clear_user_cache
from devplacepy.services.gitea import runtime
from devplacepy.services.gitea.fake import FakeGiteaClient
from devplacepy.services.gitea.client import STATE_OPEN
from devplacepy.services.gitea.config import GiteaConfig

JSON = {"Accept": "application/json"}


def _configured() -> GiteaConfig:
    return GiteaConfig(
        base_url="https://gitea.test",
        owner="retoor",
        repo="devplacepy",
        token="test-token",
        ai_enhance=False,
        ai_model="x",
        ai_key="x",
    )


@pytest.fixture
def client():
    with TestClient(app) as test_client:
        yield test_client


@pytest.fixture
def admin_headers(client):
    users = get_table("users")
    uid = get_primary_admin_uid()
    if uid is None:
        uid = generate_uid()
        users.insert(
            {
                "uid": uid,
                "username": f"gitea_admin_{uid[:8]}",
                "terms_version": "1",
                "email": f"{uid[:8]}@gitea.test",
                "role": "Admin",
                "api_key": f"giteakey_{uid}",
                "is_active": True,
                "xp": 0,
                "level": 1,
                "created_at": datetime.now(timezone.utc).isoformat(),
            }
        )
        invalidate_admins_cache()
        refresh_snapshot()
    admin = users.find_one(uid=uid)
    key = admin.get("api_key")
    if not key:
        key = f"giteakey_{uid}"
        users.update({"uid": uid, "api_key": key}, ["uid"])
        clear_user_cache(uid)
        refresh_snapshot()
    return {"X-API-KEY": key, **JSON}


@pytest.fixture
def member_headers(client):
    users = get_table("users")
    uid = generate_uid()
    key = f"giteamemberkey_{uid}"
    users.insert(
        {
            "uid": uid,
            "username": f"gitea_member_{uid[:8]}",
            "terms_version": "1",
            "email": f"{uid[:8]}@giteamember.test",
            "role": "Member",
            "api_key": key,
            "is_active": True,
            "xp": 0,
            "level": 1,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    refresh_snapshot()
    return {"X-API-KEY": key, **JSON}


@pytest.fixture
def gitea(client, monkeypatch):
    monkeypatch.setattr(
        "devplacepy.routers.issues.status.gitea_config", _configured
    )
    monkeypatch.setattr(
        "devplacepy.routers.issues.comment.gitea_config", _configured
    )
    fake = FakeGiteaClient()
    now = datetime.now(timezone.utc).isoformat()
    fake._issues[1] = {
        "number": 1,
        "title": "Existing issue",
        "body": "body",
        "state": STATE_OPEN,
        "html_url": "https://gitea.test/retoor/devplacepy/issues/1",
        "user": {"login": "devplace-bot"},
        "comments": 0,
        "created_at": now,
        "updated_at": now,
        "closed_at": None,
    }
    fake._comments[1] = []
    runtime.set_client(fake)
    yield fake
    runtime.set_client(None)
    set_setting("gitea_token", "")


def test_admin_closes_issue(client, admin_headers, gitea):
    r = client.post("/issues/1/status", data={"status": "closed"}, headers=admin_headers)
    assert r.status_code == 200, r.text[:300]
    assert gitea._issues[1]["state"] == "closed"


def test_admin_reopens_issue(client, admin_headers, gitea):
    gitea._issues[1]["state"] = "closed"
    r = client.post("/issues/1/status", data={"status": "open"}, headers=admin_headers)
    assert r.status_code == 200, r.text[:300]
    assert gitea._issues[1]["state"] == "open"


def test_member_cannot_change_status(client, member_headers, gitea):
    r = client.post("/issues/1/status", data={"status": "closed"}, headers=member_headers)
    assert r.status_code == 403
    assert gitea._issues[1]["state"] == "open"


def test_status_unknown_issue_propagates_gitea_error(client, admin_headers, gitea):
    r = client.post("/issues/999/status", data={"status": "closed"}, headers=admin_headers)
    assert r.status_code in (404, 502)


def test_status_not_configured_503(client, admin_headers):
    set_setting("gitea_token", "")
    runtime.set_client(None)
    try:
        r = client.post("/issues/1/status", data={"status": "closed"}, headers=admin_headers)
        assert r.status_code == 503
    finally:
        set_setting("gitea_token", "")


def test_member_posts_comment(client, member_headers, gitea):
    r = client.post(
        "/issues/1/comment", data={"body": "a helpful comment"}, headers=member_headers
    )
    assert r.status_code == 200, r.text[:300]
    assert len(gitea._comments[1]) == 1
    assert gitea._comments[1][0]["body"]


def test_comment_requires_auth(client, gitea):
    r = client.post("/issues/1/comment", data={"body": "hi"}, headers=JSON)
    assert r.status_code in (401, 303)
