"""
GraphQL Tests for Worktable Service.

Tests GraphQL queries and mutations for tables, records, etc.
"""
import pytest
from uuid import uuid4
from django.test import override_settings

from apps.services.worktable.models import (
    TableDefinition,
    TableColumn,
    TableRecord,
    SavedFilter,
    CustomView,
    RecordAuditLog,
    FieldType,
    RecordStatus,
)
from apps.services.worktable.graphql.types import (
    TableDefinitionType,
    TableColumnType,
    TableRecordType,
    FieldTypeEnum,
    RecordStatusEnum,
)


# ============================================================================
# Type Conversion Tests
# ============================================================================

@pytest.mark.django_db(transaction=True)
class TestGraphQLTypes:
    """Test GraphQL type conversions."""
    
    def test_table_definition_type_from_model(self, tenant, user):
        """Test TableDefinitionType.from_model conversion."""
        table = TableDefinition.objects.create(
            tenant=tenant,
            slug="test-conversion",
            name="Test Conversion",
            description="Test description",
            icon="📊",
            is_active=True,
            order=1,
            enable_audit=True,
            settings={"key": "value"},
        )
        
        # Create a column
        TableColumn.objects.create(
            table=table,
            slug="name",
            name="Name",
            field_type=FieldType.TEXT,
            order=1,
        )
        
        # Convert to GraphQL type
        gql_type = TableDefinitionType.from_model(table)
        
        assert gql_type.id == table.id
        assert gql_type.slug == "test-conversion"
        assert gql_type.name == "Test Conversion"
        assert gql_type.description == "Test description"
        assert gql_type.icon == "📊"
        assert gql_type.is_active is True
        assert gql_type.enable_audit is True
        assert gql_type.settings == {"key": "value"}
        assert len(gql_type.columns) == 1
        assert gql_type.record_count == 0
    
    def test_table_column_type_from_model(self, tenant):
        """Test TableColumnType.from_model conversion."""
        table = TableDefinition.objects.create(
            tenant=tenant,
            slug="col-test",
            name="Column Test",
        )
        
        column = TableColumn.objects.create(
            table=table,
            slug="email",
            name="Email",
            field_type=FieldType.EMAIL,
            order=1,
            is_required=True,
            is_unique=True,
            config={"validation": "email"},
        )
        
        gql_type = TableColumnType.from_model(column)
        
        assert gql_type.id == column.id
        assert gql_type.slug == "email"
        assert gql_type.name == "Email"
        assert gql_type.field_type == FieldType.EMAIL
        assert gql_type.is_required is True
        assert gql_type.is_unique is True
        assert gql_type.config == {"validation": "email"}
    
    def test_table_record_type_from_model(self, tenant, user):
        """Test TableRecordType.from_model conversion."""
        table = TableDefinition.objects.create(
            tenant=tenant,
            slug="rec-test",
            name="Record Test",
        )
        
        record = TableRecord.objects.create(
            tenant=tenant,
            table=table,
            data={"name": "Test Record", "value": 100},
            status=RecordStatus.APPROVED,
            owner=user,
        )
        
        gql_type = TableRecordType.from_model(record)
        
        assert gql_type.id == record.id
        assert gql_type.table_id == table.id
        assert gql_type.data == {"name": "Test Record", "value": 100}
        assert gql_type.status == RecordStatus.APPROVED
        assert gql_type.owner is not None
        assert gql_type.owner.id == user.id
        assert gql_type.owner.email == user.email
    
    def test_table_record_type_without_owner(self, tenant):
        """Test TableRecordType.from_model without owner."""
        table = TableDefinition.objects.create(
            tenant=tenant,
            slug="no-owner-test",
            name="No Owner Test",
        )
        
        record = TableRecord.objects.create(
            tenant=tenant,
            table=table,
            data={"name": "No Owner"},
            owner=None,
        )
        
        gql_type = TableRecordType.from_model(record)
        
        assert gql_type.owner is None


# ============================================================================
# Enum Tests
# ============================================================================

class TestGraphQLEnums:
    """Test GraphQL enum definitions."""
    
    def test_field_type_enum_values(self):
        """Test FieldTypeEnum has all expected values."""
        expected_values = [
            "TEXT", "NUMBER", "DECIMAL", "DATE", "DATETIME",
            "BOOLEAN", "SELECT", "MULTI_SELECT", "RELATION",
            "FILE", "IMAGE", "FORMULA", "ROLLUP", "LOOKUP",
            "USER", "EMAIL", "URL", "PHONE", "JSON",
        ]
        
        for value in expected_values:
            assert hasattr(FieldTypeEnum, value)
    
    def test_record_status_enum_values(self):
        """Test RecordStatusEnum has all expected values."""
        expected_values = [
            "DRAFT", "PENDING", "APPROVED", "REJECTED", "ARCHIVED",
        ]
        
        for value in expected_values:
            assert hasattr(RecordStatusEnum, value)
    
    def test_field_type_enum_actual_values(self):
        """Test FieldTypeEnum actual string values."""
        assert FieldTypeEnum.TEXT.value == "text"
        assert FieldTypeEnum.NUMBER.value == "number"
        assert FieldTypeEnum.EMAIL.value == "email"
        assert FieldTypeEnum.JSON.value == "json"
    
    def test_record_status_enum_actual_values(self):
        """Test RecordStatusEnum actual string values."""
        assert RecordStatusEnum.DRAFT.value == "draft"
        assert RecordStatusEnum.APPROVED.value == "approved"
        assert RecordStatusEnum.ARCHIVED.value == "archived"


# ============================================================================
# Schema Tests
# ============================================================================

class TestGraphQLSchema:
    """Test GraphQL schema structure."""
    
    def test_schema_loads(self):
        """Test that schema loads without errors."""
        from apps.api.graphql.schema import schema
        
        assert schema is not None
    
    def test_schema_has_query(self):
        """Test that schema has Query type."""
        from apps.api.graphql.schema import schema
        
        # Check query type exists through introspection
        query = """
            query {
                __schema {
                    queryType {
                        name
                    }
                }
            }
        """
        result = schema.execute_sync(query)
        assert result.errors is None
        assert result.data["__schema"]["queryType"]["name"] == "Query"
    
    def test_schema_has_mutation(self):
        """Test that schema has Mutation type."""
        from apps.api.graphql.schema import schema
        
        # Check mutation type exists through introspection  
        query = """
            query {
                __schema {
                    mutationType {
                        name
                    }
                }
            }
        """
        result = schema.execute_sync(query)
        assert result.errors is None
        assert result.data["__schema"]["mutationType"]["name"] == "Mutation"
    
    def test_worktable_query_fields(self):
        """Test that WorktableQuery fields are available."""
        from apps.api.graphql.schema import schema
        
        # Get query fields through introspection
        query = """
            query {
                __type(name: "Query") {
                    fields {
                        name
                    }
                }
            }
        """
        result = schema.execute_sync(query)
        assert result.errors is None
        
        field_names = [f["name"] for f in result.data["__type"]["fields"]]
        
        # Check worktable query fields are present
        assert "tables" in field_names
        assert "table" in field_names
        assert "records" in field_names
        assert "record" in field_names
    
    def test_worktable_mutation_fields(self):
        """Test that WorktableMutation fields are available."""
        from apps.api.graphql.schema import schema
        
        # Get mutation fields through introspection
        query = """
            query {
                __type(name: "Mutation") {
                    fields {
                        name
                    }
                }
            }
        """
        result = schema.execute_sync(query)
        assert result.errors is None
        
        field_names = [f["name"] for f in result.data["__type"]["fields"]]
        
        # Check worktable mutation fields are present
        assert "createTable" in field_names
        assert "updateTable" in field_names
        assert "deleteTable" in field_names
        assert "createRecord" in field_names


# ============================================================================
# Query Execution Tests
# ============================================================================

@pytest.mark.django_db(transaction=True)
class TestGraphQLQueryExecution:
    """Test GraphQL query execution."""
    
    def test_tables_query_execution(self, tenant):
        """Test executing tables query."""
        from apps.api.graphql.schema import schema
        
        # Create test tables
        TableDefinition.objects.create(
            tenant=tenant,
            slug="query-test-1",
            name="Query Test 1",
            is_active=True,
        )
        TableDefinition.objects.create(
            tenant=tenant,
            slug="query-test-2",
            name="Query Test 2",
            is_active=True,
        )
        
        query = """
            query {
                tables {
                    slug
                    name
                    isActive
                }
            }
        """
        
        # Execute with mock context
        class MockRequest:
            def __init__(self, tenant):
                self.tenant = tenant
                self.user = None
        
        context = {"request": MockRequest(tenant)}
        result = schema.execute_sync(query, context_value=context)
        
        # Note: This may fail if tenant isolation isn't working in test
        # The test validates the query structure and execution
        assert result.errors is None or len(result.errors) == 0
    
    def test_hello_query_execution(self):
        """Test executing hello query (base query)."""
        from apps.api.graphql.schema import schema
        
        query = """
            query {
                hello
                version
            }
        """
        
        result = schema.execute_sync(query)
        
        assert result.errors is None
        assert result.data["hello"] == "Hello from Nexa Platform GraphQL!"
        assert result.data["version"] == "0.1.0"


# ============================================================================
# Input Type Tests
# ============================================================================

class TestGraphQLInputTypes:
    """Test GraphQL input type definitions."""
    
    def test_column_input_creation(self):
        """Test ColumnInput type can be created."""
        from apps.services.worktable.graphql.types import ColumnInput
        
        column_input = ColumnInput(
            slug="test-col",
            name="Test Column",
            field_type=FieldTypeEnum.TEXT,
            is_required=True,
        )
        
        assert column_input.slug == "test-col"
        assert column_input.name == "Test Column"
        assert column_input.field_type == FieldTypeEnum.TEXT
        assert column_input.is_required is True
    
    def test_record_input_creation(self):
        """Test RecordInput type can be created."""
        from apps.services.worktable.graphql.types import RecordInput
        
        record_input = RecordInput(
            data={"name": "Test", "value": 100},
            status=RecordStatusEnum.DRAFT,
        )
        
        assert record_input.data == {"name": "Test", "value": 100}
        assert record_input.status == RecordStatusEnum.DRAFT
    
    def test_filter_condition_input_creation(self):
        """Test FilterConditionInput type can be created."""
        from apps.services.worktable.graphql.types import FilterConditionInput
        
        filter_input = FilterConditionInput(
            field="name",
            operator="eq",
            value="Test",
        )
        
        assert filter_input.field == "name"
        assert filter_input.operator == "eq"
        assert filter_input.value == "Test"


# ============================================================================
# Pagination Type Tests  
# ============================================================================

class TestGraphQLPaginationTypes:
    """Test GraphQL pagination type definitions."""
    
    def test_page_info_creation(self):
        """Test PageInfo type can be created."""
        from apps.services.worktable.graphql.types import PageInfo
        
        page_info = PageInfo(
            has_next_page=True,
            has_previous_page=False,
            total_count=100,
            page=1,
            page_size=20,
            total_pages=5,
        )
        
        assert page_info.has_next_page is True
        assert page_info.has_previous_page is False
        assert page_info.total_count == 100
        assert page_info.page == 1
        assert page_info.page_size == 20
        assert page_info.total_pages == 5
    
    def test_table_record_connection_creation(self):
        """Test TableRecordConnection type can be created."""
        from apps.services.worktable.graphql.types import (
            TableRecordConnection,
            PageInfo,
        )
        
        connection = TableRecordConnection(
            page_info=PageInfo(
                has_next_page=False,
                has_previous_page=False,
                total_count=0,
                page=1,
                page_size=20,
                total_pages=0,
            ),
            nodes=[],
        )
        
        assert connection.page_info.total_count == 0
        assert len(connection.nodes) == 0


# ============================================================================
# Result Type Tests
# ============================================================================

class TestGraphQLResultTypes:
    """Test GraphQL result type definitions."""
    
    def test_mutation_result_success(self):
        """Test MutationResult type for success."""
        from apps.services.worktable.graphql.types import MutationResult
        
        result = MutationResult(
            success=True,
            message="Operation completed successfully",
            errors=None,
        )
        
        assert result.success is True
        assert result.message == "Operation completed successfully"
        assert result.errors is None
    
    def test_mutation_result_failure(self):
        """Test MutationResult type for failure."""
        from apps.services.worktable.graphql.types import MutationResult
        
        result = MutationResult(
            success=False,
            message="Operation failed",
            errors=["Error 1", "Error 2"],
        )
        
        assert result.success is False
        assert result.message == "Operation failed"
        assert len(result.errors) == 2
    
    def test_bulk_operation_result(self):
        """Test BulkOperationResult type."""
        from apps.services.worktable.graphql.types import BulkOperationResult
        
        result = BulkOperationResult(
            success_count=8,
            error_count=2,
            errors=[{"id": "1", "error": "Invalid data"}],
        )
        
        assert result.success_count == 8
        assert result.error_count == 2
        assert len(result.errors) == 1
