import uuid
from unittest.mock import patch

import pytest
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.pool import StaticPool
from storage.base import Base
from storage.org import Org
from storage.org_member import OrgMember
from storage.org_member_store import OrgMemberStore
from storage.role import Role
from storage.user import User
from storage.user_settings import UserSettings

from openhands.app_server.settings.settings_models import Settings


def test_get_kwargs_from_user_settings_uses_agent_settings_as_source_of_truth():
    user_settings = UserSettings(
        llm_api_key='legacy-secret',
        agent_settings={
            'agent': 'CodeActAgent',
            'llm': {
                'model': 'anthropic/claude-sonnet-4-5-20250929',
                'base_url': 'https://api.example.com',
            },
            'condenser': {
                'enabled': False,
                'max_size': 128,
            },
        },
        conversation_settings={
            'confirmation_mode': True,
            'security_analyzer': 'llm',
            'max_iterations': 42,
        },
    )

    kwargs = OrgMemberStore.get_kwargs_from_user_settings(user_settings)

    assert kwargs['llm_api_key'] == 'legacy-secret'
    assert kwargs['agent_settings_diff']['agent'] == 'CodeActAgent'
    assert (
        kwargs['agent_settings_diff']['llm']['model']
        == 'anthropic/claude-sonnet-4-5-20250929'
    )
    assert kwargs['agent_settings_diff']['llm']['base_url'] == 'https://api.example.com'
    assert kwargs['agent_settings_diff']['condenser']['enabled'] is False
    assert kwargs['agent_settings_diff']['condenser']['max_size'] == 128
    assert kwargs['conversation_settings_diff']['confirmation_mode'] is True
    assert kwargs['conversation_settings_diff']['security_analyzer'] == 'llm'
    assert kwargs['conversation_settings_diff']['max_iterations'] == 42


def test_get_kwargs_from_settings_starts_members_without_agent_setting_overrides():
    settings = Settings()
    settings.update(
        {
            'agent_settings_diff': {
                'agent': 'CodeActAgent',
                'llm': {
                    'model': 'anthropic/claude-sonnet-4-5-20250929',
                    'base_url': 'https://api.example.com',
                    'api_key': 'member-secret',
                },
            },
            'conversation_settings_diff': {
                'max_iterations': 42,
                'confirmation_mode': True,
            },
        }
    )

    kwargs = OrgMemberStore.get_kwargs_from_settings(settings)

    assert kwargs['llm_api_key'].get_secret_value() == 'member-secret'
    assert kwargs['agent_settings_diff'] == {}


@pytest.fixture
async def async_engine():
    """Create an async SQLite engine for testing."""
    engine = create_async_engine(
        'sqlite+aiosqlite:///:memory:',
        poolclass=StaticPool,
        connect_args={'check_same_thread': False},
        echo=False,
    )

    # Create all tables
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    yield engine

    await engine.dispose()


@pytest.fixture
async def async_session_maker(async_engine):
    """Create an async session maker for testing."""
    return async_sessionmaker(async_engine, class_=AsyncSession, expire_on_commit=False)


@pytest.mark.asyncio
async def test_get_org_members(async_session_maker):
    # Test getting org_members by org ID
    async with async_session_maker() as session:
        # Create test data
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        user1 = User(id=uuid.uuid4(), current_org_id=org.id)
        user2 = User(id=uuid.uuid4(), current_org_id=org.id)
        role = Role(name='admin', rank=1)
        session.add_all([user1, user2, role])
        await session.flush()

        org_member1 = OrgMember(
            org_id=org.id,
            user_id=user1.id,
            role_id=role.id,
            llm_api_key='test-key-1',
            status='active',
        )
        org_member2 = OrgMember(
            org_id=org.id,
            user_id=user2.id,
            role_id=role.id,
            llm_api_key='test-key-2',
            status='active',
        )
        session.add_all([org_member1, org_member2])
        await session.commit()
        org_id = org.id

    # Test retrieval
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        org_members = await OrgMemberStore.get_org_members(org_id)
        assert len(org_members) == 2
        api_keys = [om.llm_api_key.get_secret_value() for om in org_members]
        assert 'test-key-1' in api_keys
        assert 'test-key-2' in api_keys


@pytest.mark.asyncio
async def test_get_user_orgs(async_session_maker):
    # Test getting org_members by user ID
    async with async_session_maker() as session:
        # Create test data
        org1 = Org(name='test-org-1')
        org2 = Org(name='test-org-2')
        session.add_all([org1, org2])
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org1.id)
        role = Role(name='admin', rank=1)
        session.add_all([user, role])
        await session.flush()

        org_member1 = OrgMember(
            org_id=org1.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key-1',
            status='active',
        )
        org_member2 = OrgMember(
            org_id=org2.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key-2',
            status='active',
        )
        session.add_all([org_member1, org_member2])
        await session.commit()
        user_id = user.id

    # Test retrieval
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        org_members = await OrgMemberStore.get_user_orgs(user_id)
        assert len(org_members) == 2
        api_keys = [ou.llm_api_key.get_secret_value() for ou in org_members]
        assert 'test-key-1' in api_keys
        assert 'test-key-2' in api_keys


@pytest.mark.asyncio
async def test_get_org_member(async_session_maker):
    # Test getting org_member by org and user ID
    async with async_session_maker() as session:
        # Create test data
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id)
        role = Role(name='admin', rank=1)
        session.add_all([user, role])
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id
        user_id = user.id

    # Test retrieval
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        retrieved_org_member = await OrgMemberStore.get_org_member(org_id, user_id)
        assert retrieved_org_member is not None
        assert retrieved_org_member.org_id == org_id
        assert retrieved_org_member.user_id == user_id
        assert retrieved_org_member.llm_api_key.get_secret_value() == 'test-key'


@pytest.mark.asyncio
async def test_get_org_member_for_current_org(async_session_maker):
    # Test getting org_member for user's current organization
    async with async_session_maker() as session:
        # Create test data - user belongs to two orgs but current_org is org1
        org1 = Org(name='test-org-1')
        org2 = Org(name='test-org-2')
        session.add_all([org1, org2])
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org1.id)
        role = Role(name='admin', rank=1)
        session.add_all([user, role])
        await session.flush()

        org_member1 = OrgMember(
            org_id=org1.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key-1',
            status='active',
        )
        org_member2 = OrgMember(
            org_id=org2.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key-2',
            status='active',
        )
        session.add_all([org_member1, org_member2])
        await session.commit()
        user_id = user.id
        org1_id = org1.id

    # Test retrieval - should return org_member for current_org (org1)
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        retrieved_org_member = await OrgMemberStore.get_org_member_for_current_org(
            user_id
        )
        assert retrieved_org_member is not None
        assert retrieved_org_member.org_id == org1_id
        assert retrieved_org_member.user_id == user_id
        assert retrieved_org_member.llm_api_key.get_secret_value() == 'test-key-1'


@pytest.mark.asyncio
async def test_get_org_member_for_current_org_user_not_found(async_session_maker):
    # Test getting org_member for non-existent user
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        retrieved_org_member = await OrgMemberStore.get_org_member_for_current_org(
            uuid.uuid4()
        )
        assert retrieved_org_member is None


@pytest.mark.asyncio
async def test_add_user_to_org(async_session_maker):
    # Test adding a user to an org
    async with async_session_maker() as session:
        # Create test data
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id)
        role = Role(name='admin', rank=1)
        session.add_all([user, role])
        await session.commit()
        org_id = org.id
        user_id = user.id
        role_id = role.id

    # Test creation
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        org_member = await OrgMemberStore.add_user_to_org(
            org_id=org_id,
            user_id=user_id,
            role_id=role_id,
            llm_api_key='new-test-key',
            status='active',
        )

        assert org_member is not None
        assert org_member.org_id == org_id
        assert org_member.user_id == user_id
        assert org_member.role_id == role_id
        assert org_member.llm_api_key.get_secret_value() == 'new-test-key'
        assert org_member.status == 'active'


@pytest.mark.asyncio
async def test_add_user_to_org_with_llm_settings(async_session_maker):
    """Test that add_user_to_org correctly sets inherited LLM settings from organization."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org-llm')
        session.add(org)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id)
        role = Role(name='member', rank=2)
        session.add_all([user, role])
        await session.commit()
        org_id = org.id
        user_id = user.id
        role_id = role.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        org_member = await OrgMemberStore.add_user_to_org(
            org_id=org_id,
            user_id=user_id,
            role_id=role_id,
            llm_api_key='test-api-key',
            status='active',
            agent_settings_diff={
                'schema_version': 1,
                'llm': {
                    'model': 'claude-sonnet-4',
                    'base_url': 'https://api.example.com',
                },
                'max_iterations': 50,
            },
        )

    # Assert
    assert org_member is not None
    assert org_member.agent_settings_diff['llm']['model'] == 'claude-sonnet-4'
    assert (
        org_member.agent_settings_diff['llm']['base_url'] == 'https://api.example.com'
    )
    assert org_member.agent_settings_diff['max_iterations'] == 50


@pytest.mark.asyncio
async def test_update_user_role_in_org(async_session_maker):
    # Test updating user role in org
    async with async_session_maker() as session:
        # Create test data
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id)
        role1 = Role(name='admin', rank=1)
        role2 = Role(name='user', rank=2)
        session.add_all([user, role1, role2])
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role1.id,
            llm_api_key='test-key',
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id
        user_id = user.id
        role2_id = role2.id

    # Test update
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        updated_org_member = await OrgMemberStore.update_user_role_in_org(
            org_id=org_id, user_id=user_id, role_id=role2_id, status='inactive'
        )

        assert updated_org_member is not None
        assert updated_org_member.role_id == role2_id
        assert updated_org_member.status == 'inactive'


@pytest.mark.asyncio
async def test_update_user_role_in_org_not_found(async_session_maker):
    # Test updating org_member that doesn't exist
    from uuid import uuid4

    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        updated_org_member = await OrgMemberStore.update_user_role_in_org(
            org_id=uuid4(), user_id=uuid4(), role_id=1
        )
        assert updated_org_member is None


@pytest.mark.asyncio
async def test_remove_user_from_org(async_session_maker):
    # Test removing a user from an org
    async with async_session_maker() as session:
        # Create test data
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id)
        role = Role(name='admin', rank=1)
        session.add_all([user, role])
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id
        user_id = user.id

    # Test removal
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        result = await OrgMemberStore.remove_user_from_org(org_id, user_id)
        assert result is True

        # Verify it's removed
        retrieved_org_member = await OrgMemberStore.get_org_member(org_id, user_id)
        assert retrieved_org_member is None


@pytest.mark.asyncio
async def test_remove_user_from_org_not_found(async_session_maker):
    # Test removing user from org that doesn't exist
    from uuid import uuid4

    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        result = await OrgMemberStore.remove_user_from_org(uuid4(), uuid4())
        assert result is False


@pytest.mark.asyncio
async def test_get_org_members_paginated_basic(async_session_maker):
    """Test basic pagination returns correct number of items."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        # Create 5 users
        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(5)
        ]
        session.add_all(users)
        await session.flush()

        # Create org members
        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=3
        )

        # Assert
        assert len(members) == 3
        assert has_more is True
        # Verify user and role relationships are loaded
        assert all(member.user is not None for member in members)
        assert all(member.role is not None for member in members)


@pytest.mark.asyncio
async def test_get_org_members_paginated_no_more(async_session_maker):
    """Test pagination when there are no more results."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        # Create 3 users
        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(3)
        ]
        session.add_all(users)
        await session.flush()

        # Create org members
        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=5
        )

        # Assert
        assert len(members) == 3
        assert has_more is False


@pytest.mark.asyncio
async def test_get_org_members_paginated_exact_limit(async_session_maker):
    """Test pagination when results exactly match limit."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        # Create exactly 5 users
        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(5)
        ]
        session.add_all(users)
        await session.flush()

        # Create org members
        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=5
        )

        # Assert
        assert len(members) == 5
        assert has_more is False


@pytest.mark.asyncio
async def test_get_org_members_paginated_with_offset(async_session_maker):
    """Test pagination with offset skips correct number of items."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        # Create 10 users
        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(10)
        ]
        session.add_all(users)
        await session.flush()

        # Create org members
        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act - Get first page
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        first_page, has_more_first = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=3
        )

        # Get second page
        second_page, has_more_second = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=3, limit=3
        )

        # Assert
        assert len(first_page) == 3
        assert has_more_first is True
        assert len(second_page) == 3
        assert has_more_second is True

        # Verify no overlap between pages
        first_user_ids = {member.user_id for member in first_page}
        second_user_ids = {member.user_id for member in second_page}
        assert first_user_ids.isdisjoint(second_user_ids)


@pytest.mark.asyncio
async def test_get_org_members_paginated_empty_org(async_session_maker):
    """Test pagination with empty organization returns empty list."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=10
        )

        # Assert
        assert len(members) == 0
        assert has_more is False


@pytest.mark.asyncio
async def test_get_org_members_paginated_ordering(async_session_maker):
    """Test that pagination orders results by user_id."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        # Create users with specific IDs to test ordering
        user_ids = [uuid.uuid4() for _ in range(5)]
        user_ids.sort()  # Sort to verify ordering

        users = [
            User(id=user_id, current_org_id=org.id, email=f'user{i}@example.com')
            for i, user_id in enumerate(user_ids)
        ]
        session.add_all(users)
        await session.flush()

        # Create org members in reverse order to test that ordering works
        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user_id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user_id in enumerate(reversed(user_ids))
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=10
        )

        # Assert
        assert len(members) == 5
        # Verify members are ordered by user_id
        member_user_ids = [member.user_id for member in members]
        assert member_user_ids == sorted(member_user_ids)


@pytest.mark.asyncio
async def test_get_org_members_paginated_eager_loading(async_session_maker):
    """Test that user and role relationships are eagerly loaded."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='owner', rank=10)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='test@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=10
        )

        # Assert
        assert len(members) == 1
        member = members[0]
        # Verify relationships are loaded (not lazy)
        assert member.user is not None
        assert member.user.email == 'test@example.com'
        assert member.role is not None
        assert member.role.name == 'owner'
        assert member.role.rank == 10


@pytest.mark.asyncio
async def test_get_org_members_count_no_filter(async_session_maker):
    """Test get_org_members_count returns correct count without email filter."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(5)
        ]
        session.add_all(users)
        await session.flush()

        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        count = await OrgMemberStore.get_org_members_count(org_id=org_id)

    # Assert
    assert count == 5


@pytest.mark.asyncio
async def test_get_org_members_count_with_email_filter(async_session_maker):
    """Test get_org_members_count filters by email correctly."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email='alice@example.com'),
            User(id=uuid.uuid4(), current_org_id=org.id, email='bob@example.com'),
            User(
                id=uuid.uuid4(), current_org_id=org.id, email='alice.smith@example.com'
            ),
        ]
        session.add_all(users)
        await session.flush()

        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        count = await OrgMemberStore.get_org_members_count(
            org_id=org_id, email_filter='alice'
        )

    # Assert
    assert count == 2


@pytest.mark.asyncio
async def test_get_org_members_paginated_with_email_filter(async_session_maker):
    """Test get_org_members_paginated filters by email correctly."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email='alice@example.com'),
            User(id=uuid.uuid4(), current_org_id=org.id, email='bob@example.com'),
            User(id=uuid.uuid4(), current_org_id=org.id, email='charlie@example.com'),
        ]
        session.add_all(users)
        await session.flush()

        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key=f'test-key-{i}',
                status='active',
            )
            for i, user in enumerate(users)
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=10, email_filter='bob'
        )

    # Assert
    assert len(members) == 1
    assert members[0].user.email == 'bob@example.com'
    assert has_more is False


@pytest.mark.asyncio
async def test_get_org_members_paginated_email_filter_case_insensitive(
    async_session_maker,
):
    """Test email filter is case-insensitive."""
    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='admin', rank=1)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='Alice@Example.COM')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act
    with patch('storage.org_member_store.a_session_maker', async_session_maker):
        members, has_more = await OrgMemberStore.get_org_members_paginated(
            org_id=org_id, offset=0, limit=10, email_filter='alice@example'
        )

    # Assert
    assert len(members) == 1
    assert members[0].user.email == 'Alice@Example.COM'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_with_llm_api_key(
    async_session_maker,
):
    """
    GIVEN: Organization with members and llm_api_key in member settings
    WHEN: update_all_members_settings_async is called with llm_api_key
    THEN: The llm_api_key is encrypted and stored in _llm_api_key column for all members
    """
    from server.routes.org_models import OrgMemberSettingsUpdate
    from storage.encrypt_utils import decrypt_value

    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        users = [
            User(id=uuid.uuid4(), current_org_id=org.id, email=f'user{i}@example.com')
            for i in range(2)
        ]
        session.add_all(users)
        await session.flush()

        org_members = [
            OrgMember(
                org_id=org.id,
                user_id=user.id,
                role_id=role.id,
                llm_api_key='old-key',
                status='active',
            )
            for user in users
        ]
        session.add_all(org_members)
        await session.commit()
        org_id = org.id

    # Act
    new_api_key = 'new-test-api-key-12345'
    member_settings = OrgMemberSettingsUpdate(llm_api_key=new_api_key)

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        updated_members = result.scalars().all()

        assert len(updated_members) == 2
        for member in updated_members:
            # Verify the encrypted value can be decrypted to the original
            decrypted_key = decrypt_value(member._llm_api_key)
            assert decrypted_key == new_api_key


@pytest.mark.asyncio
async def test_update_all_members_settings_async_with_non_encrypted_fields(
    async_session_maker,
):
    """
    GIVEN: Organization with members
    WHEN: update_all_members_settings_async is called with non-encrypted fields
    THEN: The fields are updated directly without encryption
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'schema_version': 1,
                'llm': {'model': 'old-model'},
                'max_iterations': 10,
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'llm': {
                'model': 'new-model',
                'base_url': 'https://new-url.com',
            },
            'max_iterations': 50,
        }
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        updated_member = result.scalars().first()

        assert updated_member.agent_settings_diff['llm']['model'] == 'new-model'
        assert (
            updated_member.agent_settings_diff['llm']['base_url']
            == 'https://new-url.com'
        )
        assert updated_member.agent_settings_diff['max_iterations'] == 50


@pytest.mark.asyncio
async def test_update_all_members_settings_async_with_empty_settings(
    async_session_maker,
):
    """
    GIVEN: Organization with members and empty member settings
    WHEN: update_all_members_settings_async is called with no fields set
    THEN: No database update is performed
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='original-key',
            agent_settings_diff={
                'schema_version': 1,
                'llm': {'model': 'original-model'},
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Empty settings (all None)
    member_settings = OrgMemberSettingsUpdate()

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Original values should be unchanged
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        assert member.agent_settings_diff['llm']['model'] == 'original-model'
        # Original key should still be there (encrypted)
        assert member._llm_api_key is not None


@pytest.mark.asyncio
async def test_update_all_members_settings_async_replaces_mcp_config(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing mcp_config in agent_settings_diff
    WHEN: update_all_members_settings_async is called with fewer MCP servers
    THEN: mcp_config should be replaced (not merged), so deleted servers stay deleted

    This tests the fix for APP-1862: MCP server settings cannot be updated
    or deleted because deep_merge was resurrecting deleted servers.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has 3 MCP servers
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'mcp_config': {
                    'mcpServers': {
                        'server1': {'url': 'https://server1.com', 'transport': 'sse'},
                        'server2': {'url': 'https://server2.com', 'transport': 'sse'},
                        'server3': {'url': 'https://server3.com', 'transport': 'sse'},
                    },
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update with only 2 servers (delete server3)
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'mcp_config': {
                'mcpServers': {
                    'server1': {'url': 'https://server1.com', 'transport': 'sse'},
                    'server2': {'url': 'https://server2.com', 'transport': 'sse'},
                    # server3 is deleted
                },
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Only 2 servers should remain, server3 should NOT be resurrected
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        mcp_servers = member.agent_settings_diff.get('mcp_config', {}).get(
            'mcpServers', {}
        )
        assert len(mcp_servers) == 2, f'Expected 2 servers, got {len(mcp_servers)}'
        assert 'server1' in mcp_servers
        assert 'server2' in mcp_servers
        assert (
            'server3' not in mcp_servers
        ), 'Deleted server was resurrected by deep_merge'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_replaces_acp_env(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing acp_env in agent_settings_diff
    WHEN: update_all_members_settings_async is called with fewer env vars
    THEN: acp_env should be replaced (not merged), so deleted vars stay deleted

    acp_env has the same replacement semantics as mcp_config.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has 3 env vars
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'acp_env': {
                    'VAR1': 'value1',
                    'VAR2': 'value2',
                    'VAR3': 'value3',
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update with only 2 vars (delete VAR3)
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'acp_env': {
                'VAR1': 'value1',
                'VAR2': 'value2',
                # VAR3 is deleted
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Only 2 vars should remain, VAR3 should NOT be resurrected
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        acp_env = member.agent_settings_diff.get('acp_env', {})
        assert len(acp_env) == 2, f'Expected 2 vars, got {len(acp_env)}'
        assert 'VAR1' in acp_env
        assert 'VAR2' in acp_env
        assert 'VAR3' not in acp_env, 'Deleted var was resurrected by deep_merge'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_mcp_config_not_in_payload(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing mcp_config
    WHEN: update_all_members_settings_async is called WITHOUT mcp_config in payload
    THEN: mcp_config should remain unchanged (not be cleared)

    This ensures we only replace mcp_config when it's explicitly in the update.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has MCP servers
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'mcp_config': {
                    'mcpServers': {
                        'server1': {'url': 'https://server1.com', 'transport': 'sse'},
                    },
                },
                'llm': {'model': 'old-model'},
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update only llm settings, NOT mcp_config
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'llm': {'model': 'new-model'},
            # mcp_config is NOT in the payload
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - mcp_config should still exist with server1
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        # LLM should be updated
        assert member.agent_settings_diff['llm']['model'] == 'new-model'
        # mcp_config should be unchanged
        mcp_config = member.agent_settings_diff.get('mcp_config', {})
        assert 'server1' in mcp_config.get('mcpServers', {})


@pytest.mark.asyncio
async def test_update_all_members_settings_async_empty_mcp_config(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing mcp_config
    WHEN: update_all_members_settings_async is called with empty mcp_config
    THEN: mcp_config should be cleared (all servers deleted)

    This tests the case where user deletes ALL servers.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has MCP servers
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'mcp_config': {
                    'mcpServers': {
                        'server1': {'url': 'https://server1.com', 'transport': 'sse'},
                        'server2': {'url': 'https://server2.com', 'transport': 'sse'},
                    },
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update with empty mcp_config (delete all servers)
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'mcp_config': {
                'mcpServers': {},  # Empty - all servers deleted
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - mcp_config should be empty
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        mcp_config = member.agent_settings_diff.get('mcp_config', {})
        mcp_servers = mcp_config.get('mcpServers', {})
        assert len(mcp_servers) == 0, f'Expected 0 servers, got {len(mcp_servers)}'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_add_first_mcp_server(
    async_session_maker,
):
    """
    GIVEN: Organization members with NO existing mcp_config
    WHEN: update_all_members_settings_async is called with mcp_config
    THEN: mcp_config should be added correctly

    This tests adding the first server when none exist.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has NO mcp_config
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'llm': {'model': 'some-model'},
                # No mcp_config
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Add first MCP server
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'mcp_config': {
                'mcpServers': {
                    'first-server': {'url': 'https://first.com', 'transport': 'sse'},
                },
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Server should be added
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        mcp_config = member.agent_settings_diff.get('mcp_config', {})
        mcp_servers = mcp_config.get('mcpServers', {})
        assert len(mcp_servers) == 1
        assert 'first-server' in mcp_servers


@pytest.mark.asyncio
async def test_update_all_members_settings_async_update_server_url(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing mcp_config
    WHEN: update_all_members_settings_async is called with updated server URL
    THEN: The server URL should be updated (not duplicated)

    This tests updating an existing server's properties.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'mcp_config': {
                    'mcpServers': {
                        'myserver': {
                            'url': 'https://old-url.com',
                            'transport': 'sse',
                        },
                    },
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update server URL
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'mcp_config': {
                'mcpServers': {
                    'myserver': {
                        'url': 'https://new-url.com',
                        'transport': 'sse',
                    },
                },
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - URL should be updated
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        mcp_config = member.agent_settings_diff.get('mcp_config', {})
        mcp_servers = mcp_config.get('mcpServers', {})
        assert len(mcp_servers) == 1
        assert mcp_servers['myserver']['url'] == 'https://new-url.com'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_acp_env_not_in_payload(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing acp_env
    WHEN: update_all_members_settings_async is called WITHOUT acp_env in payload
    THEN: acp_env should remain unchanged (not be cleared)

    This ensures we only replace acp_env when it's explicitly in the update.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has env vars
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'acp_env': {
                    'SECRET_KEY': 'secret-value',
                    'API_TOKEN': 'token-value',
                },
                'llm': {'model': 'old-model'},
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update only llm settings, NOT acp_env
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'llm': {'model': 'new-model'},
            # acp_env is NOT in the payload
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - acp_env should still exist with both vars
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        # LLM should be updated
        assert member.agent_settings_diff['llm']['model'] == 'new-model'
        # acp_env should be unchanged
        acp_env = member.agent_settings_diff.get('acp_env', {})
        assert 'SECRET_KEY' in acp_env
        assert 'API_TOKEN' in acp_env


@pytest.mark.asyncio
async def test_update_all_members_settings_async_empty_acp_env(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing acp_env
    WHEN: update_all_members_settings_async is called with empty acp_env
    THEN: acp_env should be cleared (all vars deleted)

    This tests the case where user deletes ALL env vars.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has env vars
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'acp_env': {
                    'VAR1': 'value1',
                    'VAR2': 'value2',
                    'VAR3': 'value3',
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update with empty acp_env (delete all vars)
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'acp_env': {},  # Empty - all vars deleted
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - acp_env should be empty
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        acp_env = member.agent_settings_diff.get('acp_env', {})
        assert len(acp_env) == 0, f'Expected 0 vars, got {len(acp_env)}'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_add_first_acp_env_var(
    async_session_maker,
):
    """
    GIVEN: Organization members with NO existing acp_env
    WHEN: update_all_members_settings_async is called with acp_env
    THEN: acp_env should be added correctly

    This tests adding the first env var when none exist.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange - Create org with member that has NO acp_env
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'llm': {'model': 'some-model'},
                # No acp_env
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Add first env var
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'acp_env': {
                'FIRST_VAR': 'first-value',
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Env var should be added
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        acp_env = member.agent_settings_diff.get('acp_env', {})
        assert len(acp_env) == 1
        assert 'FIRST_VAR' in acp_env
        assert acp_env['FIRST_VAR'] == 'first-value'


@pytest.mark.asyncio
async def test_update_all_members_settings_async_update_acp_env_value(
    async_session_maker,
):
    """
    GIVEN: Organization members with existing acp_env
    WHEN: update_all_members_settings_async is called with updated var value
    THEN: The var value should be updated

    This tests updating an existing env var's value.
    """
    from server.routes.org_models import OrgMemberSettingsUpdate

    # Arrange
    async with async_session_maker() as session:
        org = Org(name='test-org')
        session.add(org)
        await session.flush()

        role = Role(name='member', rank=2)
        session.add(role)
        await session.flush()

        user = User(id=uuid.uuid4(), current_org_id=org.id, email='user@example.com')
        session.add(user)
        await session.flush()

        org_member = OrgMember(
            org_id=org.id,
            user_id=user.id,
            role_id=role.id,
            llm_api_key='test-key',
            agent_settings_diff={
                'acp_env': {
                    'MY_SECRET': 'old-secret-value',
                },
            },
            status='active',
        )
        session.add(org_member)
        await session.commit()
        org_id = org.id

    # Act - Update env var value
    member_settings = OrgMemberSettingsUpdate(
        agent_settings_diff={
            'acp_env': {
                'MY_SECRET': 'new-secret-value',
            },
        },
    )

    async with async_session_maker() as session:
        await OrgMemberStore.update_all_members_settings_async(
            session, org_id, member_settings
        )
        await session.commit()

    # Assert - Value should be updated
    async with async_session_maker() as session:
        from sqlalchemy import select

        result = await session.execute(
            select(OrgMember).filter(OrgMember.org_id == org_id)
        )
        member = result.scalars().first()

        acp_env = member.agent_settings_diff.get('acp_env', {})
        assert len(acp_env) == 1
        assert acp_env['MY_SECRET'] == 'new-secret-value'
