# retoor <retoor@molodetz.nl>

import asyncio
import pytest
from devplacepy.database import (
    get_table,
    init_db,
    refresh_snapshot,
    set_setting,
)
from devplacepy.services.gitea import runtime, store
from devplacepy.services.gitea.config import gitea_config
from devplacepy.services.gitea.enhance import enhance_ticket
from devplacepy.services.gitea.fake import FakeGiteaClient
from devplacepy.services.gitea.service import IssueTrackerService
from devplacepy.services.jobs import queue
from devplacepy.services.jobs.issue_create_service import IssueCreateService
from tests.conftest import run_async
_counter_issues_gitea = [0]
@pytest.fixture(autouse=True)
def _init_db_issues_gitea():
    init_db()
    yield
@pytest.fixture
def gitea_env():
    fake = FakeGiteaClient()
    runtime.set_client(fake)
    set_setting("gitea_base_url", "https://gitea.test")
    set_setting("gitea_owner", "retoor")
    set_setting("gitea_repo", "pydevplace")
    set_setting("gitea_token", "test-token")
    set_setting("issue_ai_enhance", "0")
    yield fake
    runtime.set_client(None)
    for table in ("issue_tickets", "issue_comment_authors"):
        for row in list(get_table(table).find()):
            get_table(table).delete(uid=row["uid"])
    for row in list(get_table("jobs").find(kind="issue_create")):
        get_table("jobs").delete(uid=row["uid"])
def _make_user_issues_gitea():
    _counter_issues_gitea[0] += 1
    uid = f"issuetest-user-{_counter_issues_gitea[0]}"
    username = f"issuetester{_counter_issues_gitea[0]}"
    get_table("users").insert(
        {
            "uid": uid,
            "username": username,
            "role": "member",
            "xp": 0,
            "level": 1,
            "is_active": True,
        }
    )
    return uid, username
def _unread(user_uid):
    return [
        n
        for n in get_table("notifications").find(user_uid=user_uid)
        if n.get("type") == "issue"
    ]
def _drive_jobs():
    async def run():
        svc = IssueCreateService()
        for _ in range(200):
            await svc.run_once()
            refresh_snapshot()
            pending = [
                r
                for r in get_table("jobs").find(kind="issue_create")
                if r["status"] in ("pending", "running")
            ]
            if not pending and not svc._inflight:
                return
            await asyncio.sleep(0.02)

    run_async(run())
def _role_user(role: str):
    uid, username = _make_user_issues_gitea()
    get_table("users").update({"uid": uid, "role": role}, ["uid"])
    return uid, username
def _open_ticket(fake, role: str):
    import devplacepy.main as m
    from starlette.testclient import TestClient
    from devplacepy.utils import create_session

    uid, _ = _role_user(role)
    issue = run_async(fake.create_issue("Submit does nothing", "details"))
    number = int(issue["number"])
    store.record_ticket(
        number=number,
        author_uid=uid,
        original_title="Submit does nothing",
        original_description="details",
        enhanced_title="Submit does nothing",
        html_url=issue.get("html_url", ""),
        status="open",
    )
    client = TestClient(m.app)
    client.cookies.set("session", create_session(uid))
    return number, client


def test_fake_client_create_and_list(gitea_env):
    async def go():
        issue = await gitea_env.create_issue("Crash on save", "details")
        assert issue["number"] == 1
        assert issue["state"] == "open"
        issues, total = await gitea_env.list_issues(state="open")
        assert total == 1
        assert issues[0]["number"] == 1

    run_async(go())


def test_fake_client_state_and_comments(gitea_env):
    async def go():
        issue = await gitea_env.create_issue("t", "b")
        number = issue["number"]
        await gitea_env.create_comment(number, "first")
        fetched = await gitea_env.get_issue(number)
        assert fetched["comments"] == 1
        closed = await gitea_env.set_state(number, "closed")
        assert closed["state"] == "closed"
        open_issues, _ = await gitea_env.list_issues(state="open")
        assert open_issues == []
        all_issues, total = await gitea_env.list_issues(state="all")
        assert total == 1

    run_async(go())


def test_store_records_and_maps(gitea_env):
    uid, _ = _make_user_issues_gitea()
    store.record_ticket(7, uid, "orig", "desc", "Better", "https://x/7", "open")
    assert store.author_uid_for_issue(7) == uid
    assert store.author_map([7, 8]) == {7: uid}
    cid = store.record_comment_author(99, 7, uid)
    assert cid
    assert store.comment_author_map([99, 100]) == {99: uid}
    assert store.local_comment_ids(7) == {99}


def test_enhance_fallback_when_disabled(gitea_env):
    result = run_async(enhance_ticket("Title", "Body text", gitea_config()))
    assert result.enhanced is False
    assert "## Summary" in result.body
    assert "## Steps to Reproduce" in result.body
    assert result.title == "Title"


def test_create_job_files_issue(gitea_env):
    uid, username = _make_user_issues_gitea()
    job_uid = queue.enqueue(
        "issue_create",
        {"author_uid": uid, "title": "Login broken", "description": "cannot log in"},
        "user",
        uid,
        "Login broken",
    )
    _drive_jobs()
    job = queue.get_job(job_uid)
    assert job["status"] == "done"
    number = job["result"]["number"]
    assert number == 1
    ticket = store.get_ticket(number)
    assert ticket["author_uid"] == uid
    assert _unread(uid)
    issue = run_async(gitea_env.get_issue(number))
    assert username in issue["body"]


def test_create_job_fails_without_config(gitea_env):
    set_setting("gitea_token", "")
    uid, _ = _make_user_issues_gitea()
    job_uid = queue.enqueue(
        "issue_create",
        {"author_uid": uid, "title": "x", "description": "y"},
        "user",
        uid,
        "x",
    )
    _drive_jobs()
    job = queue.get_job(job_uid)
    assert job["status"] == "failed"
    assert "not configured" in job["error"].lower()


def test_poller_notifies_on_developer_reply(gitea_env):
    uid, _ = _make_user_issues_gitea()
    issue = run_async(gitea_env.create_issue("issue", "body"))
    number = issue["number"]
    store.record_ticket(number, uid, "issue", "body", "issue", issue["html_url"], "open")
    store.update_ticket_cache(number, "open", 0)

    gitea_env.add_external_comment(number, "developer", "looking into it")
    before = len(_unread(uid))
    run_async(IssueTrackerService().run_once())
    refresh_snapshot()
    assert len(_unread(uid)) == before + 1
    assert int(store.get_ticket(number)["last_comment_count"]) == 1


def test_poller_ignores_local_comment(gitea_env):
    uid, _ = _make_user_issues_gitea()
    issue = run_async(gitea_env.create_issue("issue", "body"))
    number = issue["number"]
    store.record_ticket(number, uid, "issue", "body", "issue", issue["html_url"], "open")
    store.update_ticket_cache(number, "open", 0)

    comment = run_async(gitea_env.create_comment(number, "me again"))
    store.record_comment_author(comment["id"], number, uid)
    before = len(_unread(uid))
    run_async(IssueTrackerService().run_once())
    refresh_snapshot()
    assert len(_unread(uid)) == before


def test_poller_notifies_on_status_change(gitea_env):
    uid, _ = _make_user_issues_gitea()
    issue = run_async(gitea_env.create_issue("issue", "body"))
    number = issue["number"]
    store.record_ticket(number, uid, "issue", "body", "issue", issue["html_url"], "open")
    store.update_ticket_cache(number, "open", 0)

    run_async(gitea_env.set_state(number, "closed"))
    before = len(_unread(uid))
    run_async(IssueTrackerService().run_once())
    refresh_snapshot()
    assert len(_unread(uid)) == before + 1
    assert store.get_ticket(number)["last_status"] == "closed"
