"""
Tests for field_roles update functionality.
[AC-MRS-01] 验证字段角色更新功能
"""

import pytest
import uuid
from unittest.mock import AsyncMock, MagicMock

from app.models.entities import (
    MetadataFieldDefinition,
    MetadataFieldDefinitionUpdate,
    MetadataFieldStatus,
)
from app.services.metadata_field_definition_service import MetadataFieldDefinitionService


class TestFieldRolesUpdate:
    """测试字段角色更新功能"""

    @pytest.fixture
    def mock_session(self):
        """Create mock session"""
        session = MagicMock()
        session.execute = AsyncMock()
        session.flush = AsyncMock()
        session.commit = AsyncMock()
        return session

    @pytest.fixture
    def service(self, mock_session):
        """Create service instance"""
        return MetadataFieldDefinitionService(mock_session)

    @pytest.fixture
    def existing_field(self):
        """Create existing field with field_roles"""
        field = MagicMock(spec=MetadataFieldDefinition)
        field.id = uuid.uuid4()
        field.tenant_id = "test-tenant"
        field.field_key = "grade"
        field.label = "年级"
        field.type = "string"
        field.required = True
        field.options = None
        field.default_value = None
        field.scope = ["kb_document"]
        field.is_filterable = True
        field.is_rank_feature = False
        field.field_roles = ["slot"]  # 初始角色
        field.status = MetadataFieldStatus.ACTIVE.value
        field.version = 1
        return field

    @pytest.mark.asyncio
    async def test_update_field_roles_success(self, service, mock_session, existing_field):
        """[AC-MRS-01] 测试成功更新字段角色"""
        # Mock get_field_definition to return existing field
        service.get_field_definition = AsyncMock(return_value=existing_field)
        
        # Create update request with new field_roles
        field_update = MetadataFieldDefinitionUpdate(
            field_roles=["slot", "resource_filter"]
        )
        
        # Execute update
        result = await service.update_field_definition(
            "test-tenant",
            str(existing_field.id),
            field_update
        )
        
        # Verify result
        assert result is not None
        assert result.field_roles == ["slot", "resource_filter"]
        assert result.version == 2  # Version should increment

    @pytest.mark.asyncio
    async def test_update_field_roles_to_empty(self, service, mock_session, existing_field):
        """[AC-MRS-01] 测试将字段角色更新为空列表"""
        service.get_field_definition = AsyncMock(return_value=existing_field)
        
        field_update = MetadataFieldDefinitionUpdate(
            field_roles=[]
        )
        
        result = await service.update_field_definition(
            "test-tenant",
            str(existing_field.id),
            field_update
        )
        
        assert result is not None
        assert result.field_roles == []

    @pytest.mark.asyncio
    async def test_update_field_roles_invalid_role(self, service, mock_session, existing_field):
        """[AC-MRS-01] 测试更新无效的字段角色"""
        service.get_field_definition = AsyncMock(return_value=existing_field)
        
        field_update = MetadataFieldDefinitionUpdate(
            field_roles=["invalid_role"]
        )
        
        with pytest.raises(ValueError) as exc_info:
            await service.update_field_definition(
                "test-tenant",
                str(existing_field.id),
                field_update
            )
        
        assert "无效的字段角色" in str(exc_info.value)

    @pytest.mark.asyncio
    async def test_update_without_field_roles_unchanged(self, service, mock_session, existing_field):
        """[AC-MRS-01] 测试不更新 field_roles 时保持原值"""
        service.get_field_definition = AsyncMock(return_value=existing_field)
        
        # Update only label, not field_roles
        field_update = MetadataFieldDefinitionUpdate(
            label="新年级标签"
        )
        
        result = await service.update_field_definition(
            "test-tenant",
            str(existing_field.id),
            field_update
        )
        
        assert result is not None
        assert result.label == "新年级标签"
        assert result.field_roles == ["slot"]  # Should remain unchanged

    @pytest.mark.asyncio
    async def test_update_field_roles_not_found(self, service, mock_session):
        """[AC-MRS-01] 测试更新不存在的字段"""
        service.get_field_definition = AsyncMock(return_value=None)
        
        field_update = MetadataFieldDefinitionUpdate(
            field_roles=["slot"]
        )
        
        result = await service.update_field_definition(
            "test-tenant",
            str(uuid.uuid4()),
            field_update
        )
        
        assert result is None
