from types import SimpleNamespace

import pytest
from src.core.exceptions import ValidationError
from src.domain.github_user_mirror.schemas import GithubUserInstallationCreate
from src.domain.github_user_mirror.service import parse_github_installation_id


@pytest.mark.parametrize(
    ("raw", "expected"),
    [
        ("128683971", 128683971),
        ("https://github.com/settings/installations/128683971", 128683971),
        (
            "https://github.com/organizations/Pie-Solutions/settings/installations/128683971",
            128683971,
        ),
        (
            "https://github.com/organizations/Pie-Solutions/settings/installations/128683971?state=active",
            128683971,
        ),
    ],
)
def test_parse_github_installation_id_accepts_github_settings_urls(raw, expected):
    assert parse_github_installation_id(raw) == expected


@pytest.mark.parametrize(
    "raw",
    [
        "",
        "https://example.com/settings/installations/128683971",
        "https://github.com/organizations/Pie-Solutions/settings/apps/p2hs-client",
    ],
)
def test_parse_github_installation_id_rejects_invalid_values(raw):
    with pytest.raises(ValidationError):
        parse_github_installation_id(raw)


def test_github_user_installation_create_requires_id_or_url():
    with pytest.raises(ValueError):
        GithubUserInstallationCreate()

    assert GithubUserInstallationCreate(installation_id=128683971).installation_id == 128683971
    assert (
        GithubUserInstallationCreate(
            installation_url="https://github.com/settings/installations/128683971"
        ).installation_url
        == "https://github.com/settings/installations/128683971"
    )


@pytest.mark.asyncio
async def test_confirm_installation_allows_same_github_installation_in_different_workspaces(
    monkeypatch,
):
    from unittest.mock import AsyncMock
    from uuid import uuid4

    from src.domain.github_user_mirror.service import GithubUserMirrorService

    class FakeGitHubUserAppClient:
        async def get_installation(self, installation_id: int):
            assert installation_id == 128683971
            return {
                "repository_selection": "selected",
                "account": {"login": "octo-user", "id": 42, "type": "User"},
            }

    monkeypatch.setattr(
        "src.domain.github_user_mirror.service.GitHubUserAppClient",
        FakeGitHubUserAppClient,
    )

    workspace_a = uuid4()
    workspace_b = uuid4()
    created = []

    installation_repo = AsyncMock()
    installation_repo.get_by_workspace_and_github_installation_id = AsyncMock(return_value=None)

    async def create(**kwargs):
        created.append(kwargs)
        row = AsyncMock()
        row.workspace_id = kwargs["workspace_id"]
        row.github_installation_id = kwargs["github_installation_id"]
        return row

    installation_repo.create = AsyncMock(side_effect=create)

    svc = GithubUserMirrorService(installation_repo, AsyncMock(), AsyncMock())
    await svc.confirm_installation(
        workspace_id=workspace_a,
        user_id=uuid4(),
        installation_id=128683971,
        state=None,
    )
    await svc.confirm_installation(
        workspace_id=workspace_b,
        user_id=uuid4(),
        installation_id=128683971,
        state=None,
    )

    assert [row["workspace_id"] for row in created] == [workspace_a, workspace_b]


@pytest.mark.asyncio
@pytest.mark.parametrize(
    ("event", "action"),
    [
        ("installation", "new_permissions_accepted"),
        ("installation_repositories", None),
    ],
)
async def test_github_installation_selection_webhooks_update_all_workspace_rows(
    monkeypatch,
    event,
    action,
):
    from src.domain.github_user_mirror import webhook_handlers

    rows = [
        SimpleNamespace(id="row-a", repository_selection="all"),
        SimpleNamespace(id="row-b", repository_selection="all"),
    ]
    calls = {"flush": 0}

    class FakeInstallationRepo:
        def __init__(self, db):
            pass

        async def list_by_github_installation_id(self, installation_id: int):
            assert installation_id == 128683971
            return rows

        async def flush(self):
            calls["flush"] += 1

    monkeypatch.setattr(
        webhook_handlers,
        "WorkspaceUserGithubInstallationRepository",
        FakeInstallationRepo,
    )

    payload = {
        "installation": {
            "id": 128683971,
            "repository_selection": "selected",
        }
    }
    if action:
        payload["action"] = action

    result = await webhook_handlers.dispatch(None, event, payload)

    assert result["count"] == 2
    assert [row.repository_selection for row in rows] == ["selected", "selected"]
    assert calls["flush"] == 1
