"""New-project default roles are the v2 presets, with fixed tiers and a protected owner.

Golden fixture rule: provisioning must produce this exact set for every new project.
"""

from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import AsyncMock
from uuid import uuid4

import pytest
from src.domain.project_auth.permissions import (
    ADMIN_PRESET,
    MEMBER_PRESET,
    OWNER_PRESET,
    STAFF_PRESET,
)
from src.domain.project_auth.service import ProjectAuthService


class _FakeRoles:
    def __init__(self):
        self.created = []

    async def list_for_project(self, _project_id):
        return []

    async def create(self, **kwargs):
        self.created.append(kwargs)
        return SimpleNamespace(name=kwargs["name"])


def _service(roles):
    return ProjectAuthService(
        config_repo=SimpleNamespace(_db=None),
        key_repo=SimpleNamespace(),
        role_repo=roles,
        cloud_client=SimpleNamespace(),
    )


@pytest.mark.asyncio
async def test_new_project_seeds_four_v2_roles_with_fixed_tiers():
    roles = _FakeRoles()
    await _service(roles)._ensure_default_roles(uuid4())
    by_name = {r["name"]: r for r in roles.created}

    assert set(by_name) == {"member", "staff", "admin", "super_admin"}
    assert by_name["member"]["assignment_tier"].value == "member"
    assert by_name["staff"]["assignment_tier"].value == "staff"
    assert by_name["admin"]["assignment_tier"].value == "admin"
    assert by_name["super_admin"]["assignment_tier"] is None

    assert by_name["member"]["permissions_json"] == list(MEMBER_PRESET)
    assert by_name["staff"]["permissions_json"] == list(STAFF_PRESET)
    assert by_name["admin"]["permissions_json"] == list(ADMIN_PRESET)
    assert by_name["super_admin"]["permissions_json"] == list(OWNER_PRESET)


@pytest.mark.asyncio
async def test_owner_role_is_protected_and_no_admin_role_carries_legacy_super_admin():
    roles = _FakeRoles()
    await _service(roles)._ensure_default_roles(uuid4())
    by_name = {r["name"]: r for r in roles.created}

    assert by_name["super_admin"]["protected"] is True
    for name in ("member", "staff", "admin"):
        assert by_name[name].get("protected", False) is False
        assert "super_admin" not in by_name[name]["permissions_json"]
    assert "super_admin" not in by_name["super_admin"]["permissions_json"]


@pytest.mark.asyncio
async def test_seeding_is_idempotent_when_roles_already_exist():
    roles = _FakeRoles()
    roles.list_for_project = AsyncMock(return_value=[
        SimpleNamespace(name=n, is_default=(n == "member"))
        for n in ("member", "staff", "admin", "super_admin")
    ])
    await _service(roles)._ensure_default_roles(uuid4())
    assert roles.created == []
