# app/modules/tenancy/tests/integration/test_admin_store_roles_api.py
"""
Integration tests for admin store role management API endpoints.

Tests the admin role management endpoints at:
    /api/v1/admin/store-roles

Authentication: Uses super_admin_headers and platform_admin_headers
fixtures from tests/fixtures/auth_fixtures.py.
"""

import uuid

import pytest

from app.modules.tenancy.models import (
    Merchant,
    Platform,
    Role,
    Store,
    StorePlatform,
    User,
)
from middleware.auth import AuthManager

# ============================================================================
# Fixtures
# ============================================================================

BASE = "/api/v1/admin/store-roles"


@pytest.fixture
def admin_store_merchant(db):
    """Create a merchant for admin role tests."""
    auth = AuthManager()
    uid = uuid.uuid4().hex[:8]
    owner = User(
        email=f"admin_role_owner_{uid}@test.com",
        username=f"admin_role_owner_{uid}",
        hashed_password=auth.hash_password("ownerpass123"),
        role="merchant_owner",
        is_active=True,
    )
    db.add(owner)
    db.flush()

    merchant = Merchant(
        name="Admin Role Test Merchant",
        owner_user_id=owner.id,
        contact_email=owner.email,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)
    return merchant


@pytest.fixture
def admin_role_store(db, admin_store_merchant):
    """Create a store for admin role tests."""
    uid = uuid.uuid4().hex[:8]
    store = Store(
        merchant_id=admin_store_merchant.id,
        store_code=f"ADMROLE_{uid.upper()}",
        subdomain=f"admrole{uid}",
        name=f"Admin Role Store {uid}",
        is_active=True,
        is_verified=True,
    )
    db.add(store)
    db.commit()
    db.refresh(store)
    return store


@pytest.fixture
def admin_role_custom(db, admin_role_store):
    """Create a custom role for update/delete tests."""
    role = Role(
        store_id=admin_role_store.id,
        name="admin_test_custom_role",
        permissions=["products.view", "orders.view"],
    )
    db.add(role)
    db.commit()
    db.refresh(role)
    return role


@pytest.fixture
def test_platform(db):
    """Create a platform for scoping tests."""
    uid = uuid.uuid4().hex[:8]
    platform = Platform(
        code=f"test_{uid}",
        name=f"Test Platform {uid}",
        is_active=True,
    )
    db.add(platform)
    db.commit()
    db.refresh(platform)
    return platform


@pytest.fixture
def store_on_platform(db, admin_role_store, test_platform):
    """Link the test store to a platform."""
    sp = StorePlatform(
        store_id=admin_role_store.id,
        platform_id=test_platform.id,
        is_active=True,
    )
    db.add(sp)
    db.commit()
    db.refresh(sp)
    return sp


# ============================================================================
# Super Admin Tests
# ============================================================================


@pytest.mark.integration
@pytest.mark.tenancy
class TestAdminListStoreRoles:
    """Tests for GET /api/v1/admin/store-roles."""

    def test_list_roles_as_super_admin(
        self, client, super_admin_headers, admin_role_store
    ):
        """Super admin can list roles for any store."""
        response = client.get(
            f"{BASE}?store_id={admin_role_store.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert "roles" in data
        assert "total" in data
        # Default preset roles should be created
        assert data["total"] >= 5

    def test_list_roles_requires_store_id(self, client, super_admin_headers):
        """GET /store-roles without store_id returns 422."""
        response = client.get(BASE, headers=super_admin_headers)
        assert response.status_code == 422

    def test_list_roles_unauthenticated(self, client, admin_role_store):
        """Unauthenticated request is rejected."""
        response = client.get(f"{BASE}?store_id={admin_role_store.id}")
        assert response.status_code in (401, 403)


@pytest.mark.integration
@pytest.mark.tenancy
class TestAdminCreateStoreRole:
    """Tests for POST /api/v1/admin/store-roles."""

    def test_create_role_as_super_admin(
        self, client, super_admin_headers, admin_role_store
    ):
        """Super admin can create a custom role for any store."""
        response = client.post(
            f"{BASE}?store_id={admin_role_store.id}",
            headers=super_admin_headers,
            json={
                "name": "admin_created_role",
                "permissions": ["products.view", "orders.view"],
            },
        )
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "admin_created_role"
        assert "products.view" in data["permissions"]

    def test_create_preset_name_rejected(
        self, client, super_admin_headers, admin_role_store
    ):
        """Cannot create a role with a preset name."""
        response = client.post(
            f"{BASE}?store_id={admin_role_store.id}",
            headers=super_admin_headers,
            json={
                "name": "manager",
                "permissions": ["products.view"],
            },
        )
        assert response.status_code == 422


@pytest.mark.integration
@pytest.mark.tenancy
class TestAdminUpdateStoreRole:
    """Tests for PUT /api/v1/admin/store-roles/{role_id}."""

    def test_update_role_as_super_admin(
        self, client, super_admin_headers, admin_role_store, admin_role_custom
    ):
        """Super admin can update a custom role."""
        response = client.put(
            f"{BASE}/{admin_role_custom.id}?store_id={admin_role_store.id}",
            headers=super_admin_headers,
            json={
                "name": "renamed_admin_role",
                "permissions": ["products.view", "products.edit"],
            },
        )
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "renamed_admin_role"
        assert "products.edit" in data["permissions"]


@pytest.mark.integration
@pytest.mark.tenancy
class TestAdminDeleteStoreRole:
    """Tests for DELETE /api/v1/admin/store-roles/{role_id}."""

    def test_delete_role_as_super_admin(
        self, client, super_admin_headers, admin_role_store, admin_role_custom
    ):
        """Super admin can delete a custom role."""
        response = client.delete(
            f"{BASE}/{admin_role_custom.id}?store_id={admin_role_store.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 204

    def test_delete_nonexistent_role(
        self, client, super_admin_headers, admin_role_store
    ):
        """Deleting nonexistent role returns 422."""
        response = client.delete(
            f"{BASE}/99999?store_id={admin_role_store.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 422


# ============================================================================
# Permission Catalog Tests
# ============================================================================


@pytest.mark.integration
@pytest.mark.tenancy
class TestAdminPermissionCatalog:
    """Tests for GET /api/v1/admin/store-roles/permissions/catalog."""

    def test_catalog_returns_categories(self, client, super_admin_headers):
        """GET /permissions/catalog returns categories with permissions."""
        response = client.get(
            f"{BASE}/permissions/catalog",
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert "categories" in data
        assert len(data["categories"]) > 0

    def test_catalog_permission_has_metadata(self, client, super_admin_headers):
        """Each permission has id, label, description, and is_owner_only."""
        response = client.get(
            f"{BASE}/permissions/catalog",
            headers=super_admin_headers,
        )
        data = response.json()
        perm = data["categories"][0]["permissions"][0]
        assert "id" in perm
        assert "label" in perm
        assert "description" in perm
        assert "is_owner_only" in perm
