from datetime import datetime
import pytest
from unittest.mock import patch, MagicMock

from geobox.enums import FieldType
from geobox.exception import NotFoundError
from geobox.file import File
from geobox.relationship import Relationship
from geobox.table import Table, TableField, TableRow
from geobox.task import Task
from geobox.user import User
from geobox.vectorlayer import VectorLayer

def test_init(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    assert table.name == mock_table_data['name']
    assert table.uuid == mock_table_data['uuid']
    assert table.data == mock_table_data
    assert table.endpoint == f'{Table.BASE_ENDPOINT}{table.uuid}/'


def test_get_tables(api, mock_table_data):
    api.get.return_value = [mock_table_data, mock_table_data]
    tables = Table.get_tables(api)
    api.get.assert_called_once_with(f'{Table.BASE_ENDPOINT}?f=json&include_settings=False&return_count=False&skip=0&limit=10&shared=False')
    assert len(tables) == 2
    assert type(tables[0]) == Table
    assert tables[0].data == mock_table_data


def test_create_table(api, mock_table_data, mock_table_field_data):
    api.post.return_value = mock_table_data
    table = Table.create_table(api,
        name=mock_table_data['name'],
        display_name=mock_table_data['display_name'],
        description=mock_table_data['description'],
        temporary=mock_table_data['temporary'],
        fields=[mock_table_field_data])
    api.post.assert_called_once_with(Table.BASE_ENDPOINT, {'name': 'test', 'temporary': False, 'fields': [mock_table_field_data]})
    assert type(table) == Table
    assert table.uuid == mock_table_data['uuid']
    assert table.data == mock_table_data


def test_get_table(api, mock_table_data):
    api.get.return_value = mock_table_data
    table = Table.get_table(api, uuid=mock_table_data['uuid'])
    api.get.assert_called_once_with(f"{Table.BASE_ENDPOINT}{mock_table_data['uuid']}/?f=json")
    assert type(table) == Table
    assert table.uuid == mock_table_data['uuid']
    assert table.data == mock_table_data


def test_get_table_by_name(api, mock_table_data):
    api.get.return_value = [mock_table_data]
    table = Table.get_table_by_name(api, name=mock_table_data['name'])
    api.get.assert_called_once_with(f"{Table.BASE_ENDPOINT}?f=json&include_settings=False&q=name+%3D+%27test%27&return_count=False&skip=0&limit=10&shared=False")
    assert type(table) == Table
    assert table.uuid == mock_table_data['uuid']
    assert table.data == mock_table_data
    # not found
    table = Table.get_table_by_name(api, name='not_found')
    assert table == None


def test_update(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    updated_data = {
        **mock_table_data,
        'name': 'update',
        'display_name': 'update display name',
        'description': 'update description',
    }

    api.put.return_value = updated_data
    result = table.update(name='update', display_name='update display name', description='update description')
    api.put.assert_called_once_with(table.endpoint, {'name': 'update', 'display_name': 'update display name', 'description': 'update description'})
    assert updated_data == result
    assert table.data == updated_data


def test_delete(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    endpoint = table.endpoint
    table.delete()
    api.delete.assert_called_once_with(endpoint)
    assert table.uuid is None
    assert table.endpoint is None


def test_get_settings(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = mock_table_data['settings']
    settings = table.settings
    assert settings == mock_table_data['settings']
    api.get.assert_called_once_with(f"{table.endpoint}settings/?f=json")


def test_update_settings(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = mock_table_data['settings']
    settings = table.settings
    settings['edit_settings']['allow_delete'] = False
    api.put.return_value = settings
    result = table.update_settings(settings)
    assert result == settings


def test_get_fields(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = [mock_table_field_data, mock_table_field_data]
    fields = table.get_fields()
    assert len(fields) == 2
    assert type(fields[0]) == TableField
    assert fields[0].data == mock_table_field_data


def test_get_field(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = [mock_table_field_data, mock_table_field_data]
    field = table.get_field(field_id=mock_table_field_data['id'])
    assert type(field) == TableField
    assert field.data == mock_table_field_data


def test_get_field_by_name(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = [mock_table_field_data, mock_table_field_data]
    field = table.get_field_by_name(mock_table_field_data['name'])
    assert type(field) == TableField
    assert field.data == mock_table_field_data


def test_get_field_not_found_error(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = [mock_table_field_data, mock_table_field_data]
    with pytest.raises(NotFoundError):
        table.get_field(10)

    with pytest.raises(NotFoundError):
        table.get_field_by_name('t')


def test_add_field(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.post.return_value = mock_table_field_data
    field = table.add_field(name='field1', data_type=FieldType.String)
    assert type(field) == TableField
    assert field.data == mock_table_field_data


def test_calculate_field(api, mock_table_data, mock_success_task_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = mock_success_task_data
    task = table.calculate_field(target_field='field1', expression='upper( field1  )')
    assert type(task) == Task
    api.post.assert_called_once_with(f"{table.endpoint}calculateField/", {'target_field': 'field1', 'expression': 'upper( field1  )', 'run_async': True}, is_json=False)


def test_calculate_field_sync(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.post.return_value = {'result': 'value'}
    result = table.calculate_field(target_field='field1', expression='upper( field1  )', run_async=False)
    assert result == {'result': 'value'}
    api.post.assert_called_once_with(f"{table.endpoint}calculateField/", {'target_field': 'field1', 'expression': 'upper( field1  )', 'run_async': False}, is_json=False)


def test_row_get_attr(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    assert row.field1 == 'TEST'
    assert row.created_at == datetime(2025, 12, 16, 8, 35, 58, 453535)

    # error
    with pytest.raises(AttributeError):
        row.test


def test_get_rows(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = [mock_table_row_data, mock_table_row_data]
    rows = table.get_rows()
    assert len(rows) == 2
    assert type(rows[0]) == TableRow
    assert rows[0].data == mock_table_row_data
    api.get.assert_called_once_with(f"{table.endpoint}rows/?f=json&skip=0&limit=100&return_count=False")


def test_get_row(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.get.return_value = mock_table_row_data
    row = table.get_row(row_id=mock_table_row_data['id'])
    assert type(row) == TableRow
    assert row.data == mock_table_row_data
    api.get.assert_called_once_with(f"{row.endpoint}?f=json")


def test_create_row(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.post.return_value = mock_table_row_data
    row = table.create_row(field1='test')
    assert type(row) == TableRow
    assert row.data == mock_table_row_data
    api.post.assert_called_once_with(f"{table.endpoint}rows/", {'field1': 'test'})


def test_import_rows(api, mock_table_data, mock_file_data, mock_success_task_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    file = File(api, mock_file_data['uuid'], mock_file_data)
    api.post.return_value = {'task_id': mock_success_task_data['uuid']}
    api.get.return_value = mock_success_task_data
    task = table.import_rows(file)
    assert type(task) == Task
    assert task.data == mock_success_task_data
    api.post.assert_called_once_with(f"{table.endpoint}import-csv/", {'file_uuid': '2228a886-870e-4a0a-8e3b-6f51efee2eae', 'file_encoding': 'utf-8', 'input_dataset': 'world_boundaries.shp', 'delimiter': ',', 'has_header': True, 'report_errors': False, 'bulk_insert': True}, is_json=False)
    api.get.assert_called_once_with(task.endpoint)


def test_export_rows(api, mock_table_data, mock_success_task_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.post.return_value = {'task_id': mock_success_task_data['uuid']}
    api.get.return_value = mock_success_task_data
    task = table.export_rows('test')
    assert type(task) == Task
    assert task.data == mock_success_task_data
    api.post.assert_called_once_with(f"{table.endpoint}export/", {'out_filename': 'test', 'out_format': 'CSV', 'zipped': False, 'run_async': True}, is_json=False)
    api.get.assert_called_once_with(task.endpoint)


def test_export_rows_sync(api, mock_table_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    api.post.return_value = {'result': 'value'}
    result = table.export_rows('test', run_async=False)
    assert result == {'result': 'value'}
    api.post.assert_called_once_with(f"{table.endpoint}export/", {'out_filename': 'test', 'out_format': 'CSV', 'zipped': False, 'run_async': False}, is_json=False)


def test_row_repr(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    assert repr(row) == f"TableRow(id={row.id}, table_name={table.name})"


def test_row_update(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    updated_data = mock_table_row_data
    updated_data['properties'] = {
        'field1': 'updated row'
    }
    api.put.return_value = updated_data
    result = row.update(field1='updated row')
    assert row.properties['field1'] == 'updated row'
    api.put.assert_called_once_with(row.endpoint, {'field1': 'updated row'})
    assert result == updated_data
    

def test_row_delete(api, mock_table_data, mock_table_row_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    endpoint = row.endpoint
    row.delete()
    api.delete.assert_called_once_with(endpoint)


def test_get_other_side_of_relationship(api, mock_table_data, mock_table_row_data):
    """Test _get_other_side_of_relationship method."""
    # Create a real Table and TableRow
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    # Test case 1: Table is the source
    relationship_source = MagicMock()
    relationship_source.source_id = table.id  # Table matches source_id
    relationship_source.target_id = 999  # Some other ID
    relationship_source.get_target.return_value = "target_table_or_layer"
    
    result = row._get_other_side_of_relationship(relationship_source)
    
    # Verify relationship.get_target() was called and returned correct value
    relationship_source.get_target.assert_called_once()
    assert result == "target_table_or_layer"
    
    # Test case 2: Table is the target
    relationship_target = MagicMock()
    relationship_target.source_id = 888  # Some other ID
    relationship_target.target_id = table.id  # Table matches target_id
    relationship_target.get_source.return_value = "source_table_or_layer"
    
    result = row._get_other_side_of_relationship(relationship_target)
    
    # Verify relationship.get_source() was called and returned correct value
    relationship_target.get_source.assert_called_once()
    assert result == "source_table_or_layer"
    
    # Test case 3: Table is not part of relationship (should raise ValueError)
    relationship_invalid = MagicMock()
    relationship_invalid.source_id = 777  # Different ID
    relationship_invalid.target_id = 666  # Different ID
    
    with pytest.raises(ValueError, match="Relationship does not involve this table"):
        row._get_other_side_of_relationship(relationship_invalid)


def test_fetch_related_from_target(api, mock_table_data, mock_table_row_data):
    """Test _fetch_related_from_target method."""
    # Create a real Table and TableRow
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    relationship_uuid = "12345678-1234-5678-1234-567812345678"
    
    # Test case 1: Target is a Table
    mock_table_target = MagicMock(spec=Table)
    mock_table_target.get_rows.return_value = ["row1", "row2", "row3"]
    
    result = row._fetch_related_from_target(mock_table_target, relationship_uuid)
    
    # Verify table.get_rows() was called with correct parameters
    mock_table_target.get_rows.assert_called_once_with(
        relationship_uuid=relationship_uuid,
        related_record_id=row.id
    )
    assert result == ["row1", "row2", "row3"]
    
    # Test case 2: Target is a VectorLayer
    mock_vector_target = MagicMock(spec=VectorLayer)
    mock_vector_target.get_features.return_value = ["feature1", "feature2"]
    
    result = row._fetch_related_from_target(mock_vector_target, relationship_uuid)
    
    # Verify vector_layer.get_features() was called with correct parameters
    mock_vector_target.get_features.assert_called_once_with(
        relationship_uuid=relationship_uuid,
        related_record_id=row.id
    )
    assert result == ["feature1", "feature2"]
    
    # Test case 3: Target is unsupported type (should raise TypeError)
    unsupported_target = "not_a_table_or_layer"
    
    with pytest.raises(TypeError, match=f"Unsupported target type: {type(unsupported_target)}"):
        row._fetch_related_from_target(unsupported_target, relationship_uuid)


def test_get_related_records(api, mock_table_data, mock_table_row_data, mock_relationship_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    with patch.object(row, '_get_other_side_of_relationship') as mock_get_other_side:
        with patch.object(row, '_fetch_related_from_target') as mock_fetch:
            # Setup mocks
            mock_other_side = MagicMock()
            mock_get_other_side.return_value = mock_other_side
            mock_fetch.return_value = [row, row]
            
            # Call the method
            related_records = row.get_related_records(mock_relationship_data['uuid'])
            
            # Verify
            api.get_relationship.assert_called_once_with(mock_relationship_data['uuid'])
            mock_get_other_side.assert_called_once_with(api.get_relationship.return_value)
            mock_fetch.assert_called_once_with(
                target=mock_other_side,
                relationship_uuid=mock_relationship_data['uuid']
            )
            assert related_records == [row, row]


def test_row_associate_with_target_ids(api, mock_table_data, mock_table_row_data, mock_relationship_data):
    """Test associate_with method with target_ids parameter."""
    # Create a real Table and TableRow
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    # Create a mock relationship
    mock_relationship = MagicMock()
    mock_associate_result = {
        "success": True,
        "created": 3,
        "updated": 0,
        "deleted": 0
    }
    mock_relationship.associate_records.return_value = mock_associate_result
    
    # Mock the API call to get relationship
    api.get_relationship.return_value = mock_relationship
    
    # Call the method
    target_ids = [1, 2, 3]
    result = row.associate_with(
        relationship_uuid=mock_relationship_data['uuid'],
        target_ids=target_ids
    )
    
    # Verify the calls
    api.get_relationship.assert_called_once_with(uuid=mock_relationship_data['uuid'])
    mock_relationship.associate_records.assert_called_once_with(
        source_id=row.id,
        target_ids=target_ids,
        q=None
    )
    
    # Verify the result
    assert result == mock_associate_result
    assert result["success"] is True
    assert result["created"] == 3


def test_row_associate_with_query(api, mock_table_data, mock_table_row_data, mock_relationship_data):
    """Test associate_with method with query parameter."""
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    mock_relationship = MagicMock()
    mock_associate_result = {
        "success": True,
        "created": 5,
        "updated": 0,
        "deleted": 0
    }
    mock_relationship.associate_records.return_value = mock_associate_result
    
    api.get_relationship.return_value = mock_relationship
    
    # Call with query parameter
    query = "field1 = 'test' AND field2 > 10"
    result = row.associate_with(
        relationship_uuid=mock_relationship_data['uuid'],
        q=query
    )
    
    # Verify the calls
    api.get_relationship.assert_called_once_with(uuid=mock_relationship_data['uuid'])
    mock_relationship.associate_records.assert_called_once_with(
        source_id=row.id,
        target_ids=None,
        q=query
    )
    
    assert result == mock_associate_result


def test_row_disassociate_with_target_ids(api, mock_table_data, mock_table_row_data, mock_relationship_data):
    """Test disassociate_with method with target_ids parameter."""
    # Create a real Table and TableRow
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    # Create a mock relationship
    mock_relationship = MagicMock()
    mock_disassociate_result = {
        "success": True,
        "created": 3,
        "updated": 0,
        "deleted": 0
    }
    mock_relationship.disassociate_records.return_value = mock_disassociate_result
    
    # Mock the API call to get relationship
    api.get_relationship.return_value = mock_relationship
    
    # Call the method
    target_ids = [1, 2, 3]
    result = row.disassociate_with(
        relationship_uuid=mock_relationship_data['uuid'],
        target_ids=target_ids
    )
    
    # Verify the calls
    api.get_relationship.assert_called_once_with(uuid=mock_relationship_data['uuid'])
    mock_relationship.disassociate_records.assert_called_once_with(
        source_id=row.id,
        target_ids=target_ids,
        q=None
    )
    
    # Verify the result
    assert result == mock_disassociate_result
    assert result["success"] is True
    assert result["created"] == 3


def test_row_disassociate_with_query(api, mock_table_data, mock_table_row_data, mock_relationship_data):
    """Test disassociate_with method with query parameter."""
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    row = TableRow(table, mock_table_row_data)
    
    mock_relationship = MagicMock()
    mock_disassociate_result = {
        "success": True,
        "created": 5,
        "updated": 0,
        "deleted": 0
    }
    mock_relationship.disassociate_records.return_value = mock_disassociate_result
    
    api.get_relationship.return_value = mock_relationship
    
    # Call with query parameter
    query = "field1 = 'test' AND field2 > 10"
    result = row.disassociate_with(
        relationship_uuid=mock_relationship_data['uuid'],
        q=query
    )
    
    # Verify the calls
    api.get_relationship.assert_called_once_with(uuid=mock_relationship_data['uuid'])
    mock_relationship.disassociate_records.assert_called_once_with(
        source_id=row.id,
        target_ids=None,
        q=query
    )
    
    assert result == mock_disassociate_result


def test_field_data_type(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    assert field.datatype == FieldType.String


def test_field_init_datatype_error(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    with pytest.raises(ValueError):
        TableField(table, data_type='string', field_id=mock_table_field_data['id'], data=mock_table_field_data)


def test_field_repr(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    assert repr(field) == f'TableField(id={field.id}, name={field.name}, data_type={field.data_type})'


def test_field_get_domain(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    assert field.domain == mock_table_field_data['domain']
    

def test_field_set_domain(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    domain = {
        'min': 10,
        'max': 20,
        'items': {}
    }
    field.domain = domain
    assert field.domain == domain


def test_field_delete(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    endpoint = field.endpoint
    field.delete()
    api.delete.assert_called_once_with(endpoint)


def test_field_update(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    updated_data = {
        'name': 'updated_name',
        'display_name': 'updated display name',
        'description': 'updated description',
        'domain': {'min': 11, 'max': 22},
        'hyperlink': True
    }
    api.put.return_value = updated_data
    result = field.update(**updated_data)
    for key, value in updated_data.items():
        assert field.data[key] == value

    assert result == updated_data
    api.put.assert_called_once_with(field.endpoint, updated_data)


def test_field_update_domain(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    field.domain = None
    domain = {'min': 15, 'max': 25, 'items': {'1': 'test1', '2': 'test2'}}
    api.put.return_value = {
        **mock_table_field_data,
        **domain
    }
    result = field.update_domain(range_domain={'min': 15, 'max': 25}, list_domain={'1': 'test1', '2': 'test2'})
    assert result == field.domain


def test_field_add_index(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    api.post.return_value = mock_table_field_data
    result = field.add_index()
    assert result == mock_table_field_data
    api.post.assert_called_once_with(endpoint=f"{field.endpoint}addIndex/")


def test_field_remove_index(api, mock_table_data, mock_table_field_data):
    table = Table(api, mock_table_data['uuid'], mock_table_data)
    field = TableField(table, data_type=FieldType.String, field_id=mock_table_field_data['id'], data=mock_table_field_data)
    api.post.return_value = mock_table_field_data
    result = field.remove_index()
    assert result == mock_table_field_data
    api.post.assert_called_once_with(endpoint=f"{field.endpoint}removeIndex/")


def test_share(api, mock_table_data, mock_user_data):
    """Test file sharing."""
    with patch.object(api, 'post'):
        table = Table(api, uuid=mock_table_data['uuid'], data=mock_table_data)
        users = [
            User(api, user_id=mock_user_data['1']['id'], data=mock_user_data['1']),
            User(api, user_id=mock_user_data['2']['id'], data=mock_user_data['2'])
        ]
        table.share(users=users)
        api.post.assert_called_once_with(
            f'{table.endpoint}share/',
            {'user_ids': [1, 2]}, is_json=False
        )


def test_unshare(api, mock_table_data, mock_user_data):
    """Test file unsharing."""
    with patch.object(api, 'post'):
        table = Table(api, uuid=mock_table_data['uuid'], data=mock_table_data)
        users = [
            User(api, user_id=mock_user_data['1']['id'], data=mock_user_data['1']),
            User(api, user_id=mock_user_data['2']['id'], data=mock_user_data['2'])
        ]
        table.unshare(users=users)
        
        # Verify the API call
        api.post.assert_called_once_with(
            f'{table.endpoint}unshare/',
            {'user_ids': [1, 2]}, is_json=False
        )


def test_get_shared_users(api, mock_table_data, mock_user_data):
    """Test getting shared users."""
    mock_response = [
        mock_user_data['1'],
        mock_user_data['2']
    ]
    
    with patch.object(api, 'get', return_value=mock_response):
        table = Table(api, uuid=mock_table_data['uuid'], data=mock_table_data)
        result = table.get_shared_users(search='user', limit=2)

        api.get.assert_called_once_with(
            f'{table.endpoint}shared-with-users/?search=user&skip=0&limit=2'
        )

        assert len(result) == 2
        assert result[0].first_name == 'test 1'
        assert result[0].last_name == 'test 1'
        assert result[1].first_name == 'test 2'
        assert result[1].last_name == 'test 2'


def test_get_relations(api, mock_table_data, mock_relationship_data):
    table = Table(api, uuid=mock_table_data['uuid'], data=mock_table_data)

    api.get.return_value = [mock_relationship_data]
    response = table.get_relations()
    assert isinstance(response, list)
    assert isinstance(response[0], Relationship)
    assert response[0].data == mock_relationship_data
    api.get.assert_called_once_with(f'{table.endpoint}relations/')