"""GogsAdapter のテスト。"""

from __future__ import annotations

import pytest
import responses

from gfo.adapter.gitea import GiteaAdapter
from gfo.adapter.gogs import GogsAdapter
from gfo.adapter.registry import get_adapter_class
from gfo.exceptions import NotSupportedError

BASE = "https://gogs.example.com/api/v1"
WEB_BASE = "https://gogs.example.com"
REPOS = f"{BASE}/repos/test-owner/test-repo"


def _issue_data(*, number=1, state="open"):
    return {
        "number": number,
        "title": f"Issue #{number}",
        "body": "description",
        "state": state,
        "user": {"login": "author1"},
        "assignees": [],
        "labels": [],
        "html_url": f"{WEB_BASE}/test-owner/test-repo/issues/{number}",
        "created_at": "2025-01-01T00:00:00Z",
    }


class TestRegistry:
    def test_registered(self):
        assert get_adapter_class("gogs") is GogsAdapter


class TestInheritance:
    def test_is_gitea_adapter(self, gogs_adapter):
        assert isinstance(gogs_adapter, GiteaAdapter)

    def test_service_name(self, gogs_adapter):
        assert gogs_adapter.service_name == "Gogs"


class TestNotSupportedOperations:
    def test_list_pull_requests(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.list_pull_requests()
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls"

    def test_create_pull_request(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.create_pull_request(title="PR", base="main", head="feature")
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/compare"

    def test_get_pull_request(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.get_pull_request(1)
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls/1"

    def test_merge_pull_request(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.merge_pull_request(1)
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls/1"

    def test_close_pull_request(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.close_pull_request(1)
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls/1"

    def test_get_pr_checkout_refspec(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.get_pr_checkout_refspec(1)
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls/1"

    def test_list_labels(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.list_labels()
        assert exc_info.value.web_url is None

    def test_create_label(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.create_label(name="bug")
        assert exc_info.value.web_url is None

    def test_list_milestones(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.list_milestones()
        assert exc_info.value.web_url is None

    def test_create_milestone(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.create_milestone(title="v1.0")
        assert exc_info.value.web_url is None

    def test_delete_label(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.delete_label(name="bug")
        assert exc_info.value.web_url is None

    def test_delete_milestone(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.delete_milestone(number=1)
        assert exc_info.value.web_url is None

    def test_list_releases(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.list_releases()
        assert exc_info.value.web_url is None

    def test_create_release(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.create_release(tag="v1.0.0")
        assert exc_info.value.web_url is None

    def test_delete_release(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.delete_release(tag="v1.0.0")
        assert exc_info.value.web_url is None

    def test_update_pull_request(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.update_pull_request(1, title="New")
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls"

    def test_update_comment(self, gogs_adapter):
        with pytest.raises(NotSupportedError):
            gogs_adapter.update_comment("issue", 10, body="Updated")

    def test_delete_comment(self, gogs_adapter):
        with pytest.raises(NotSupportedError):
            gogs_adapter.delete_comment("issue", 10)

    def test_list_reviews(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.list_reviews(1)
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls"

    def test_create_review(self, gogs_adapter):
        with pytest.raises(NotSupportedError) as exc_info:
            gogs_adapter.create_review(1, state="approve")
        assert exc_info.value.web_url == f"{WEB_BASE}/test-owner/test-repo/pulls"

    def test_list_pipelines(self, gogs_adapter):
        with pytest.raises(NotSupportedError):
            gogs_adapter.list_pipelines()

    def test_get_pipeline(self, gogs_adapter):
        with pytest.raises(NotSupportedError):
            gogs_adapter.get_pipeline(1)

    def test_cancel_pipeline(self, gogs_adapter):
        with pytest.raises(NotSupportedError):
            gogs_adapter.cancel_pipeline(1)


class TestWebUrl:
    def test_standard_url(self, gogs_adapter):
        assert gogs_adapter._web_url() == "https://gogs.example.com"

    def test_url_with_port(self, gogs_client):
        from gfo.http import HttpClient

        client = HttpClient(
            "http://gogs.local:3000/api/v1",
            auth_header={"Authorization": "token test-token"},
        )
        adapter = GogsAdapter(client, "owner", "repo")
        assert adapter._web_url() == "http://gogs.local:3000"

    def test_web_url_owner_repo_with_special_chars_is_encoded(self, gogs_client):
        """owner/repo に特殊文字が含まれる場合に web_url が URL エンコードされる（R34-01）。"""
        from gfo.http import HttpClient

        client = HttpClient(
            "https://gogs.example.com/api/v1",
            auth_header={"Authorization": "token test-token"},
        )
        adapter = GogsAdapter(client, "my owner", "my repo")
        with pytest.raises(NotSupportedError) as exc_info:
            adapter.list_pull_requests()
        assert "my%20owner" in exc_info.value.web_url
        assert "my%20repo" in exc_info.value.web_url


class TestInheritedOperations:
    def test_create_issue(self, mock_responses, gogs_adapter):
        mock_responses.add(
            responses.POST,
            f"{REPOS}/issues",
            json=_issue_data(),
            status=201,
        )
        issue = gogs_adapter.create_issue(title="Test", body="body")
        assert issue.number == 1

    def test_close_issue(self, mock_responses, gogs_adapter):
        mock_responses.add(
            responses.PATCH,
            f"{REPOS}/issues/1",
            json=_issue_data(state="closed"),
            status=200,
        )
        gogs_adapter.close_issue(1)

    def test_get_issue(self, mock_responses, gogs_adapter):
        mock_responses.add(
            responses.GET,
            f"{REPOS}/issues/1",
            json=_issue_data(),
            status=200,
        )
        issue = gogs_adapter.get_issue(1)
        assert issue.number == 1

    def test_list_issues(self, mock_responses, gogs_adapter):
        mock_responses.add(
            responses.GET,
            f"{REPOS}/issues",
            json=[_issue_data()],
            status=200,
        )
        issues = gogs_adapter.list_issues()
        assert len(issues) == 1
        assert issues[0].number == 1
        assert issues[0].state == "open"

    def test_list_issues_pagination(self, mock_responses, gogs_adapter):
        import json as json_mod

        next_url = f"{REPOS}/issues?page=2&limit=30"
        call_count = {"n": 0}

        def callback(request):
            call_count["n"] += 1
            if call_count["n"] == 1:
                headers = {"Link": f'<{next_url}>; rel="next"'}
                return (
                    200,
                    headers,
                    json_mod.dumps([_issue_data(number=1), _issue_data(number=2)]),
                )
            return (200, {}, json_mod.dumps([_issue_data(number=3)]))

        mock_responses.add_callback(responses.GET, f"{REPOS}/issues", callback=callback)
        issues = gogs_adapter.list_issues(limit=0)
        assert len(issues) == 3
        assert call_count["n"] == 2


class TestDeleteInheritance:
    """Gogs の delete メソッドの動作確認。"""

    def test_delete_issue_raises_not_supported(self, gogs_adapter):
        """Gogs は issue delete 未対応 → NotSupportedError。"""
        from gfo.exceptions import NotSupportedError

        with pytest.raises(NotSupportedError):
            gogs_adapter.delete_issue(5)

    def test_delete_repository(self, mock_responses, gogs_adapter):
        mock_responses.add(
            responses.DELETE,
            REPOS,
            status=204,
        )
        gogs_adapter.delete_repository()
        assert mock_responses.calls[0].request.method == "DELETE"
