"""Tests for GitHub integration endpoints."""

from unittest.mock import patch

_DB = "api.routers.github.db"
_GH = "api.routers.github.github_app"


class TestListGitHubInstallations:
    """Tests for GET /v1/github/installations."""

    def test_list_installations_success(self, client, auth_header, sample_installation):
        with patch(f"{_DB}.get_org_github_installations") as mock_installs:
            mock_installs.return_value = [sample_installation]
            response = client.get("/v1/github/installations", headers=auth_header)
            assert response.status_code == 200
            data = response.json()
            assert len(data) == 1
            assert data[0]["installation_id"] == sample_installation["installation_id"]
            assert data[0]["account_login"] == sample_installation["account_login"]

    def test_list_installations_empty(self, client, auth_header):
        with patch(f"{_DB}.get_org_github_installations") as mock_installs:
            mock_installs.return_value = []
            response = client.get("/v1/github/installations", headers=auth_header)
            assert response.status_code == 200
            assert response.json() == []

    def test_list_installations_unauthorized(self, client):
        response = client.get("/v1/github/installations")
        assert response.status_code == 401


class TestSyncGitHubInstallations:
    """Tests for POST /v1/github/installations/sync."""

    def test_sync_installations_success(self, client, auth_header):
        with patch(f"{_DB}.get_org_github_installations") as mock_existing, \
             patch(f"{_GH}.get_app_installations") as mock_gh, \
             patch(f"{_DB}.save_github_installation"), \
             patch(f"{_DB}.link_github_installation_to_org"):
            mock_existing.return_value = []
            mock_gh.return_value = [
                {
                    "id": 99999,
                    "account": {"login": "neworg", "type": "Organization"},
                },
            ]
            response = client.post(
                "/v1/github/installations/sync", headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert data["status"] == "synced"
            assert len(data["newly_linked"]) == 1

    def test_sync_installations_already_linked(self, client, auth_header):
        with patch(f"{_DB}.get_org_github_installations") as mock_existing, \
             patch(f"{_GH}.get_app_installations") as mock_gh:
            mock_existing.return_value = [{"installation_id": 12345}]
            mock_gh.return_value = [
                {"id": 12345, "account": {"login": "testorg", "type": "Organization"}},
            ]
            response = client.post(
                "/v1/github/installations/sync", headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert data["already_linked"] == 1
            assert len(data["newly_linked"]) == 0

    def test_sync_installations_unauthorized(self, client):
        response = client.post("/v1/github/installations/sync")
        assert response.status_code == 401


class TestGetGitHubSettings:
    """Tests for GET /v1/github/settings."""

    def test_get_settings_success(self, client, auth_header):
        with patch(f"{_DB}.get_github_settings") as mock_settings:
            mock_settings.return_value = {
                "org_id": "org_test456",
                "auto_debug": True,
                "post_comments": True,
                "create_checks": True,
                "auto_create_prs": False,
            }
            response = client.get("/v1/github/settings", headers=auth_header)
            assert response.status_code == 200
            data = response.json()
            assert data["auto_debug"] is True
            assert data["auto_create_prs"] is False

    def test_get_settings_unauthorized(self, client):
        response = client.get("/v1/github/settings")
        assert response.status_code == 401


class TestUpdateGitHubSettings:
    """Tests for PUT /v1/github/settings."""

    def test_update_settings_success(self, client, auth_header):
        with patch(f"{_DB}.save_github_settings") as mock_save:
            mock_save.return_value = {
                "org_id": "org_test456",
                "auto_debug": False,
                "post_comments": True,
                "create_checks": True,
                "auto_create_prs": True,
            }
            response = client.put(
                "/v1/github/settings",
                json={"auto_debug": False, "auto_create_prs": True},
                headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert data["auto_debug"] is False
            assert data["auto_create_prs"] is True

    def test_update_settings_unauthorized(self, client):
        response = client.put(
            "/v1/github/settings",
            json={"auto_debug": False},
        )
        assert response.status_code == 401


class TestAutoFix:
    """Tests for POST /v1/github/auto-fix."""

    def test_auto_fix_no_suggestions(self, client, auth_header):
        with patch(f"{_DB}.get_org_github_installations") as mock_installs, \
             patch(f"{_DB}.get_run") as mock_run:
            mock_installs.return_value = [{"installation_id": 12345}]
            mock_run.return_value = {"hypotheses": None}
            response = client.post(
                "/v1/github/auto-fix",
                json={
                    "owner": "testorg",
                    "repo": "testrepo",
                    "pr_number": 42,
                    "run_id": "550e8400-e29b-41d4-a716-446655440000",
                    "installation_id": 12345,
                },
                headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert data["status"] == "no_suggestions"

    def test_auto_fix_with_hypotheses(self, client, auth_header):
        with patch(f"{_DB}.get_org_github_installations") as mock_installs, \
             patch(f"{_DB}.get_run") as mock_run, \
             patch(f"{_GH}.post_auto_fix_suggestions") as mock_post:
            mock_installs.return_value = [{"installation_id": 12345}]
            mock_run.return_value = {
                "hypotheses": [
                    {
                        "id": "h1",
                        "root_cause": "Race condition",
                        "confidence": 0.9,
                        "patch": "--- a/test.py\n+++ b/test.py",
                        "explanation": "Fix race",
                        "strategy": "async_wait",
                    },
                ],
            }
            mock_post.return_value = {"posted": 1, "status": "success"}
            response = client.post(
                "/v1/github/auto-fix",
                json={
                    "owner": "testorg",
                    "repo": "testrepo",
                    "pr_number": 42,
                    "run_id": "550e8400-e29b-41d4-a716-446655440000",
                    "installation_id": 12345,
                },
                headers=auth_header,
            )
            assert response.status_code == 200

    def test_auto_fix_unauthorized(self, client):
        response = client.post(
            "/v1/github/auto-fix",
            json={
                "owner": "testorg",
                "repo": "testrepo",
                "pr_number": 42,
            },
        )
        assert response.status_code == 401


class TestLinkGitHubInstallation:
    """Tests for POST /v1/github/installations/link."""

    def test_link_installation_success(self, client, auth_header):
        with patch(f"{_DB}.get_github_installation") as mock_get, \
             patch(f"{_DB}.link_github_installation_to_org") as mock_link, \
             patch(f"{_GH}.get_installation_repos") as mock_repos, \
             patch(f"{_DB}.save_github_repo"):
            mock_get.return_value = {
                "installation_id": 12345,
                "account_login": "testorg",
            }
            mock_link.return_value = None
            mock_repos.return_value = [
                {
                    "id": 1, "name": "repo1",
                    "full_name": "testorg/repo1",
                    "owner": {"login": "testorg"},
                },
            ]
            response = client.post(
                "/v1/github/installations/link",
                json={"installation_id": 12345},
                headers=auth_header,
            )
            assert response.status_code == 200
            assert response.json()["status"] == "linked"

    def test_link_installation_unauthorized(self, client):
        response = client.post(
            "/v1/github/installations/link",
            json={"installation_id": 12345},
        )
        assert response.status_code == 401
