"""Comprehensive test suite for TextField and CharField."""

import pytest
from atomsql import Database, Model, StringField
from atomsql.orm.fields import TextField, CharField


# Test Models
class Article(Model):
    """Model with TextField for testing long text content."""

    title = CharField(max_length=100)
    content = TextField()
    author = StringField()


class Product(Model):
    """Model with various CharField configurations."""

    name = CharField(max_length=50, nullable=False)
    sku = CharField(max_length=20, unique=True)
    description = TextField(nullable=True)
    category = CharField(max_length=30, default="General")


class BlogPost(Model):
    """Model for testing nullable and default behaviors."""

    title = CharField(max_length=200, nullable=False)
    slug = CharField(max_length=100, unique=True, nullable=False)
    body = TextField(nullable=False)
    excerpt = TextField(nullable=True)
    tags = CharField(max_length=255, nullable=True, default=None)


class Comment(Model):
    """Model for testing TextField with various configurations."""

    author_name = CharField(max_length=100)
    comment_text = TextField(nullable=False)
    reply_to = TextField(nullable=True)


class Settings(Model):
    """Model for testing extreme cases."""

    key = CharField(max_length=50, unique=True, nullable=False)
    value = TextField(nullable=True)
    description = TextField(default="No description provided")


@pytest.fixture
def db():
    """Create an in-memory SQLite database."""
    database = Database("sqlite://:memory:")
    database.create_all()
    return database


# ============================================================================
# Tests for CharField - Basic Functionality
# ============================================================================


def test_charfield_accepts_valid_string(db):
    """Test CharField accepts a valid string within max_length."""
    article = Article.create(
        title="Hello World", content="This is a test article.", author="John Doe"
    )

    assert article.title == "Hello World"
    assert len(article.title) <= 100


def test_charfield_accepts_empty_string(db):
    """Test CharField accepts an empty string when nullable."""
    product = Product.create(name="Test Product", sku="SKU001", category="")

    assert product.category == ""


def test_charfield_accepts_string_at_max_length(db):
    """Test CharField accepts a string exactly at max_length."""
    max_length_title = "A" * 100
    article = Article.create(title=max_length_title, content="Content", author="Author")

    assert article.title == max_length_title
    assert len(article.title) == 100


def test_charfield_accepts_string_below_max_length(db):
    """Test CharField accepts a string below max_length."""
    article = Article.create(title="Short", content="Content", author="Author")

    assert article.title == "Short"
    assert len(article.title) < 100


def test_charfield_single_character(db):
    """Test CharField accepts a single character."""
    product = Product.create(name="A", sku="B", category="C")

    assert product.name == "A"
    assert product.sku == "B"
    assert product.category == "C"


def test_charfield_with_special_characters(db):
    """Test CharField accepts strings with special characters."""
    article = Article.create(
        title="Test!@#$%^&*()_+-=[]{}|;:',.<>?/~`", content="Content", author="Author"
    )

    assert "!@#$%^&*" in article.title


def test_charfield_with_unicode_characters(db):
    """Test CharField accepts Unicode characters."""
    article = Article.create(
        title="Hello 世界 🌍 Ñoño", content="Content", author="Author"
    )

    assert "世界" in article.title
    assert "🌍" in article.title
    assert "Ñoño" in article.title


def test_charfield_with_newlines_and_tabs(db):
    """Test CharField accepts strings with newlines and tabs."""
    article = Article.create(
        title="Line 1\nLine 2\tTabbed", content="Content", author="Author"
    )

    assert "\n" in article.title
    assert "\t" in article.title


def test_charfield_with_spaces(db):
    """Test CharField accepts strings with leading/trailing spaces."""
    product = Product.create(name="  Spaced Product  ", sku="SKU001")

    assert product.name == "  Spaced Product  "


def test_charfield_retrieval_from_database(db):
    """Test CharField value is correctly retrieved from database."""
    article = Article.create(title="Stored Title", content="Content", author="Author")
    article_id = article.id

    # Retrieve the article
    retrieved = Article.get(pk=article_id)
    assert retrieved.title == "Stored Title"


# ============================================================================
# Tests for CharField - max_length Parameter
# ============================================================================


def test_charfield_max_length_positive_integer():
    """Test CharField requires max_length to be a positive integer."""

    # This test validates the field definition itself
    class TestModel(Model):
        field1 = CharField(max_length=1)
        field2 = CharField(max_length=100)
        field3 = CharField(max_length=65535)

    assert TestModel.field1.max_length == 1
    assert TestModel.field2.max_length == 100
    assert TestModel.field3.max_length == 65535


def test_charfield_max_length_zero_raises_error():
    """Test CharField raises ValueError when max_length is 0."""
    with pytest.raises(ValueError, match="must be a positive integer"):

        class TestModel(Model):
            name = CharField(max_length=0)


def test_charfield_max_length_negative_raises_error():
    """Test CharField raises ValueError when max_length is negative."""
    with pytest.raises(ValueError, match="must be a positive integer"):

        class TestModel(Model):
            name = CharField(max_length=-10)


def test_charfield_max_length_non_integer_raises_error():
    """Test CharField raises ValueError when max_length is not an integer."""
    with pytest.raises(ValueError, match="must be a positive integer"):

        class TestModel(Model):
            name = CharField(max_length="100")


def test_charfield_max_length_float_raises_error():
    """Test CharField raises ValueError when max_length is a float."""
    with pytest.raises(ValueError, match="must be a positive integer"):

        class TestModel(Model):
            name = CharField(max_length=10.5)


# Note: The current implementation has a bug where validate_type returns early
# before checking max_length. These tests document the intended behavior.
# Once the bug is fixed, these tests should pass.


@pytest.mark.xfail(
    reason="Bug in CharField.validate_type - early return prevents max_length check"
)
def test_charfield_exceeds_max_length_on_create(db):
    """Test CharField raises ValueError when string exceeds max_length on create."""
    with pytest.raises(ValueError, match="max length"):
        Article.create(
            title="A" * 101,  # Exceeds max_length of 100
            content="Content",
            author="Author",
        )


@pytest.mark.xfail(
    reason="Bug in CharField.validate_type - early return prevents max_length check"
)
def test_charfield_exceeds_max_length_on_assignment(db):
    """Test CharField raises ValueError when assigned string exceeds max_length."""
    article = Article.create(title="Valid Title", content="Content", author="Author")

    with pytest.raises(ValueError, match="max length"):
        article.title = "B" * 101  # Exceeds max_length of 100


@pytest.mark.xfail(
    reason="Bug in CharField.validate_type - early return prevents max_length check"
)
def test_charfield_exceeds_max_length_unicode(db):
    """Test CharField validates length correctly with Unicode characters."""
    # Each emoji is one character in Python's len()
    emoji_string = "🌍" * 101  # 101 emojis should exceed max_length of 100

    with pytest.raises(ValueError, match="max length"):
        Article.create(title=emoji_string, content="Content", author="Author")


# ============================================================================
# Tests for CharField - nullable Parameter
# ============================================================================


def test_charfield_nullable_true_accepts_none(db):
    """Test CharField with nullable=True accepts None."""
    product = Product.create(
        name="Test Product",
        sku="SKU001",
        description=None,  # TextField with nullable=True
    )

    assert product.description is None


def test_charfield_nullable_false_rejects_none(db):
    """Test CharField with nullable=False rejects None."""
    with pytest.raises(ValueError, match="expected a str"):
        Product.create(
            name=None,  # nullable=False
            sku="SKU001",
        )


def test_charfield_nullable_true_can_be_set_to_none(db):
    """Test CharField with nullable=True can be updated to None."""
    product = Product.create(name="Test Product", sku="SKU001", category="Electronics")

    product.category = None
    assert product.category is None


def test_charfield_nullable_false_cannot_be_set_to_none(db):
    """Test CharField with nullable=False cannot be updated to None."""
    blog_post = BlogPost.create(title="Test Post", slug="test-post", body="Content")

    with pytest.raises(ValueError, match="expected a str"):
        blog_post.title = None


def test_charfield_nullable_retrieval_from_database(db):
    """Test None value is correctly stored and retrieved."""
    product = Product.create(name="Test", sku="SKU001", description=None, category=None)
    product_id = product.id

    retrieved = Product.get(pk=product_id)
    assert retrieved.description is None
    assert retrieved.category is None


# ============================================================================
# Tests for CharField - unique Parameter
# ============================================================================


def test_charfield_unique_allows_first_value(db):
    """Test CharField with unique=True allows the first value."""
    product = Product.create(name="Product 1", sku="UNIQUE001")

    assert product.sku == "UNIQUE001"


def test_charfield_unique_prevents_duplicate(db):
    """Test CharField with unique=True prevents duplicate values."""
    Product.create(name="Product 1", sku="DUPLICATE")

    with pytest.raises(Exception):  # Database constraint error
        Product.create(name="Product 2", sku="DUPLICATE")


def test_charfield_unique_allows_different_values(db):
    """Test CharField with unique=True allows different values."""
    product1 = Product.create(name="Product 1", sku="SKU001")
    product2 = Product.create(name="Product 2", sku="SKU002")

    assert product1.sku != product2.sku


def test_charfield_unique_with_none_values(db):
    """Test CharField with unique=True behavior with None values."""
    # SQLite allows multiple NULL values for unique constraints
    settings1 = Settings.create(key="key1", value=None)
    settings2 = Settings.create(key="key2", value=None)

    assert settings1.value is None
    assert settings2.value is None


# ============================================================================
# Tests for CharField - default Parameter
# ============================================================================


def test_charfield_default_string_value(db):
    """Test CharField uses default string value when not provided."""
    product = Product.create(
        name="Test Product",
        sku="SKU001",
        # category not provided, should use default
    )

    assert product.category == "General"


def test_charfield_default_none_value(db):
    """Test CharField uses default None when not provided."""
    blog_post = BlogPost.create(
        title="Test",
        slug="test",
        body="Content",
        # tags not provided, should use default None
    )

    assert blog_post.tags is None


def test_charfield_default_can_be_overridden(db):
    """Test CharField default can be overridden."""
    product = Product.create(
        name="Test Product",
        sku="SKU001",
        category="Electronics",  # Override default
    )

    assert product.category == "Electronics"
    assert product.category != "General"


def test_charfield_default_empty_string():
    """Test CharField with default empty string."""

    class TestModel(Model):
        name = CharField(max_length=50, default="")

    # Create a fresh database and register the model
    test_db = Database("sqlite://:memory:")
    test_db.register(TestModel)
    instance = TestModel.create()

    assert instance.name == ""


def test_textfield_default_value(db):
    """Test TextField uses default value when not provided."""
    settings = Settings.create(
        key="test_key",
        value="test_value",
        # description not provided, should use default
    )

    assert settings.description == "No description provided"


# ============================================================================
# Tests for CharField - Type Validation
# ============================================================================


def test_charfield_rejects_integer(db):
    """Test CharField rejects integer values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title=12345,  # Integer instead of string
            content="Content",
            author="Author",
        )


def test_charfield_rejects_float(db):
    """Test CharField rejects float values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title=123.45,  # Float instead of string
            content="Content",
            author="Author",
        )


def test_charfield_rejects_boolean(db):
    """Test CharField rejects boolean values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title=True,  # Boolean instead of string
            content="Content",
            author="Author",
        )


def test_charfield_rejects_list(db):
    """Test CharField rejects list values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(title=["not", "a", "string"], content="Content", author="Author")


def test_charfield_rejects_dict(db):
    """Test CharField rejects dictionary values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(title={"not": "a string"}, content="Content", author="Author")


def test_charfield_rejects_bytes(db):
    """Test CharField rejects bytes values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(title=b"bytes string", content="Content", author="Author")


# ============================================================================
# Tests for TextField - Basic Functionality
# ============================================================================


def test_textfield_accepts_short_string(db):
    """Test TextField accepts short strings."""
    article = Article.create(title="Title", content="Short content.", author="Author")

    assert article.content == "Short content."


def test_textfield_accepts_long_string(db):
    """Test TextField accepts very long strings."""
    long_content = "A" * 10000  # 10,000 characters
    article = Article.create(title="Title", content=long_content, author="Author")

    assert article.content == long_content
    assert len(article.content) == 10000


def test_textfield_accepts_very_long_string(db):
    """Test TextField accepts extremely long strings."""
    very_long_content = "B" * 100000  # 100,000 characters
    article = Article.create(title="Title", content=very_long_content, author="Author")

    assert len(article.content) == 100000


def test_textfield_accepts_empty_string(db):
    """Test TextField accepts empty string when nullable."""
    comment = Comment.create(
        author_name="User",
        comment_text="",  # Empty but not None
    )

    assert comment.comment_text == ""


def test_textfield_accepts_multiline_string(db):
    """Test TextField accepts multiline strings."""
    multiline_content = """Line 1
Line 2
Line 3
Line 4"""
    article = Article.create(title="Title", content=multiline_content, author="Author")

    assert article.content == multiline_content
    assert article.content.count("\n") == 3


def test_textfield_accepts_string_with_special_formatting(db):
    """Test TextField accepts strings with various formatting."""
    formatted_content = """
    Paragraph 1 with spaces.

    Paragraph 2 with \t tabs \t and \n newlines.

    Paragraph 3 with special chars: !@#$%^&*()
    """
    article = Article.create(title="Title", content=formatted_content, author="Author")

    assert article.content == formatted_content


def test_textfield_accepts_unicode_content(db):
    """Test TextField accepts Unicode content."""
    unicode_content = """
    Hello in different languages:
    English: Hello
    Spanish: Hola
    Chinese: 你好
    Japanese: こんにちは
    Arabic: مرحبا
    Emoji: 👋🌍🎉
    """
    article = Article.create(title="Title", content=unicode_content, author="Author")

    assert "你好" in article.content
    assert "👋" in article.content


def test_textfield_preserves_whitespace(db):
    """Test TextField preserves whitespace."""
    content_with_whitespace = "  Leading spaces\n\n\nMultiple newlines\t\tTabs  "
    article = Article.create(
        title="Title", content=content_with_whitespace, author="Author"
    )

    assert article.content == content_with_whitespace


def test_textfield_retrieval_from_database(db):
    """Test TextField value is correctly retrieved from database."""
    long_content = "X" * 5000
    article = Article.create(title="Title", content=long_content, author="Author")
    article_id = article.id

    retrieved = Article.get(pk=article_id)
    assert retrieved.content == long_content
    assert len(retrieved.content) == 5000


# ============================================================================
# Tests for TextField - nullable Parameter
# ============================================================================


def test_textfield_nullable_true_accepts_none(db):
    """Test TextField with nullable=True accepts None."""
    product = Product.create(name="Test", sku="SKU001", description=None)

    assert product.description is None


def test_textfield_nullable_false_rejects_none(db):
    """Test TextField with nullable=False rejects None."""
    with pytest.raises(ValueError, match="expected a str"):
        Comment.create(
            author_name="User",
            comment_text=None,  # nullable=False
        )


def test_textfield_nullable_true_can_be_set_to_none(db):
    """Test TextField with nullable=True can be updated to None."""
    blog_post = BlogPost.create(
        title="Test", slug="test", body="Content", excerpt="Initial excerpt"
    )

    blog_post.excerpt = None
    assert blog_post.excerpt is None


def test_textfield_nullable_false_cannot_be_set_to_none(db):
    """Test TextField with nullable=False cannot be updated to None."""
    blog_post = BlogPost.create(title="Test", slug="test", body="Initial content")

    with pytest.raises(ValueError, match="expected a str"):
        blog_post.body = None


# ============================================================================
# Tests for TextField - Type Validation
# ============================================================================


def test_textfield_rejects_integer(db):
    """Test TextField rejects integer values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title="Title",
            content=12345,  # Integer instead of string
            author="Author",
        )


def test_textfield_rejects_float(db):
    """Test TextField rejects float values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title="Title",
            content=123.45,  # Float instead of string
            author="Author",
        )


def test_textfield_rejects_boolean(db):
    """Test TextField rejects boolean values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title="Title",
            content=True,  # Boolean instead of string
            author="Author",
        )


def test_textfield_rejects_list(db):
    """Test TextField rejects list values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(
            title="Title", content=["list", "of", "strings"], author="Author"
        )


def test_textfield_rejects_dict(db):
    """Test TextField rejects dictionary values."""
    with pytest.raises(ValueError, match="expected a str"):
        Article.create(title="Title", content={"key": "value"}, author="Author")


# ============================================================================
# Tests for TextField and CharField - Update Operations
# ============================================================================


def test_charfield_update_with_valid_string(db):
    """Test CharField can be updated with a valid string."""
    article = Article.create(title="Original Title", content="Content", author="Author")

    article.title = "Updated Title"
    assert article.title == "Updated Title"


def test_textfield_update_with_valid_string(db):
    """Test TextField can be updated with a valid string."""
    article = Article.create(title="Title", content="Original content", author="Author")

    article.content = "Updated content"
    assert article.content == "Updated content"


def test_charfield_update_multiple_times(db):
    """Test CharField can be updated multiple times."""
    product = Product.create(name="Original", sku="SKU001")

    product.name = "Update 1"
    assert product.name == "Update 1"

    product.name = "Update 2"
    assert product.name == "Update 2"

    product.name = "Final Update"
    assert product.name == "Final Update"


def test_textfield_update_from_short_to_long(db):
    """Test TextField can be updated from short to long content."""
    article = Article.create(title="Title", content="Short", author="Author")

    long_content = "L" * 50000
    article.content = long_content
    assert len(article.content) == 50000


def test_textfield_update_from_long_to_short(db):
    """Test TextField can be updated from long to short content."""
    long_content = "L" * 50000
    article = Article.create(title="Title", content=long_content, author="Author")

    article.content = "Short"
    assert article.content == "Short"


# ============================================================================
# Tests for TextField and CharField - Edge Cases
# ============================================================================


def test_charfield_with_sql_injection_attempt(db):
    """Test CharField safely handles SQL injection attempts."""
    malicious_input = "'; DROP TABLE Article; --"
    article = Article.create(title=malicious_input, content="Content", author="Author")

    assert article.title == malicious_input
    # Verify table still exists by creating another record
    article2 = Article.create(title="Safe Title", content="Content", author="Author")
    assert article2.title == "Safe Title"


def test_textfield_with_sql_injection_attempt(db):
    """Test TextField safely handles SQL injection attempts."""
    malicious_content = """
    '; DROP TABLE Article; --
    " OR "1"="1
    '); DELETE FROM Article WHERE ('1'='1
    """
    article = Article.create(title="Title", content=malicious_content, author="Author")

    assert malicious_content in article.content


def test_charfield_with_quotes(db):
    """Test CharField handles single and double quotes."""
    title_with_quotes = """He said "Hello" and she said 'Hi'"""
    article = Article.create(
        title=title_with_quotes, content="Content", author="Author"
    )

    assert '"Hello"' in article.title
    assert "'Hi'" in article.title


def test_textfield_with_quotes(db):
    """Test TextField handles single and double quotes."""
    content_with_quotes = """
    "Double quoted text"
    'Single quoted text'
    "Nested 'quotes' inside"
    'Nested "quotes" inside'
    """
    article = Article.create(
        title="Title", content=content_with_quotes, author="Author"
    )

    assert content_with_quotes == article.content


def test_charfield_with_backslashes(db):
    """Test CharField handles backslashes."""
    title_with_backslashes = r"Path: C:\Users\Name\File.txt"
    article = Article.create(
        title=title_with_backslashes, content="Content", author="Author"
    )

    assert r"C:\Users" in article.title


def test_textfield_with_escaped_characters(db):
    """Test TextField handles various escaped characters."""
    content = r"""
    Newline: \n
    Tab: \t
    Backslash: \\
    Quote: \"
    """
    article = Article.create(title="Title", content=content, author="Author")

    assert article.content == content


def test_charfield_with_only_whitespace(db):
    """Test CharField accepts strings with only whitespace."""
    article = Article.create(
        title="     ",  # Only spaces
        content="Content",
        author="Author",
    )

    assert article.title == "     "


def test_textfield_with_only_whitespace(db):
    """Test TextField accepts strings with only whitespace."""
    whitespace_content = "   \n\n\t\t   \n   "
    article = Article.create(title="Title", content=whitespace_content, author="Author")

    assert article.content == whitespace_content


# ============================================================================
# Tests for CharField and TextField - Field Attributes
# ============================================================================


def test_charfield_has_max_length_attribute():
    """Test CharField instance has max_length attribute."""

    class TestModel(Model):
        name = CharField(max_length=42)

    assert hasattr(TestModel.name, "max_length")
    assert TestModel.name.max_length == 42


def test_charfield_inherits_from_stringfield():
    """Test CharField is a subclass of StringField."""
    from atomsql.orm.fields import StringField

    assert issubclass(CharField, StringField)


def test_textfield_inherits_from_stringfield():
    """Test TextField is a subclass of StringField."""
    from atomsql.orm.fields import StringField

    assert issubclass(TextField, StringField)


def test_charfield_has_name_attribute(db):
    """Test CharField has name attribute set."""
    _ = Article.create(title="Test", content="Content", author="Author")

    assert Article.title.name == "title"


def test_textfield_has_name_attribute(db):
    """Test TextField has name attribute set."""
    _ = Article.create(title="Test", content="Content", author="Author")

    assert Article.content.name == "content"


# ============================================================================
# Tests for CharField and TextField - Multiple Fields
# ============================================================================


def test_model_with_multiple_charfields(db):
    """Test model with multiple CharField instances."""
    blog_post = BlogPost.create(
        title="My Blog Post", slug="my-blog-post", body="Content"
    )

    assert blog_post.title == "My Blog Post"
    assert blog_post.slug == "my-blog-post"
    assert isinstance(BlogPost.title, CharField)
    assert isinstance(BlogPost.slug, CharField)


def test_model_with_multiple_textfields(db):
    """Test model with multiple TextField instances."""
    blog_post = BlogPost.create(
        title="Test", slug="test", body="Main content here", excerpt="Short excerpt"
    )

    assert blog_post.body == "Main content here"
    assert blog_post.excerpt == "Short excerpt"
    assert isinstance(BlogPost.body, TextField)
    assert isinstance(BlogPost.excerpt, TextField)


def test_model_with_mixed_charfield_textfield(db):
    """Test model with both CharField and TextField."""
    article = Article.create(
        title="Title (CharField)", content="Content (TextField)", author="Author"
    )

    assert isinstance(Article.title, CharField)
    assert isinstance(Article.content, TextField)
    assert article.title == "Title (CharField)"
    assert article.content == "Content (TextField)"


# ============================================================================
# Tests for CharField and TextField - Query Operations
# ============================================================================


def test_charfield_query_equality(db):
    """Test querying CharField with equality."""
    Article.create(title="Article 1", content="C1", author="A1")
    Article.create(title="Article 2", content="C2", author="A2")

    results = Article.filter(title="Article 1")
    assert len(results) == 1
    assert results[0].title == "Article 1"


def test_textfield_query_equality(db):
    """Test querying TextField with equality."""
    Article.create(title="T1", content="Content 1", author="A1")
    Article.create(title="T2", content="Content 2", author="A2")

    results = Article.filter(content="Content 1")
    assert len(results) == 1
    assert results[0].content == "Content 1"


def test_charfield_query_with_none(db):
    """Test querying CharField for None values."""
    p1 = Product.create(name="P1", sku="S1", category=None)
    Product.create(name="P2", sku="S2", category="Electronics")

    # Verify we can retrieve the record with None value
    retrieved = Product.get(pk=p1.id)
    assert retrieved.category is None


def test_textfield_query_with_none(db):
    """Test querying TextField for None values."""
    p1 = Product.create(name="P1", sku="S1", description=None)
    Product.create(name="P2", sku="S2", description="Has description")

    # Verify we can retrieve the record with None value
    retrieved = Product.get(pk=p1.id)
    assert retrieved.description is None


# ============================================================================
# Tests for CharField and TextField - Combination Scenarios
# ============================================================================


def test_create_with_all_field_types(db):
    """Test creating record with all field configurations."""
    blog_post = BlogPost.create(
        title="Complete Post",
        slug="complete-post",
        body="Full body content here",
        excerpt="Brief excerpt",
        tags="python,testing,atomsql",
    )

    assert blog_post.title == "Complete Post"
    assert blog_post.slug == "complete-post"
    assert blog_post.body == "Full body content here"
    assert blog_post.excerpt == "Brief excerpt"
    assert blog_post.tags == "python,testing,atomsql"


def test_create_with_minimal_required_fields(db):
    """Test creating record with only required fields."""
    blog_post = BlogPost.create(
        title="Minimal Post",
        slug="minimal-post",
        body="Body",
        # excerpt and tags are nullable
    )

    assert blog_post.title == "Minimal Post"
    assert blog_post.excerpt is None
    assert blog_post.tags is None


def test_update_multiple_fields_together(db):
    """Test updating multiple CharField and TextField together."""
    article = Article.create(
        title="Original", content="Original Content", author="Original Author"
    )

    article.title = "Updated"
    article.content = "Updated Content"
    article.author = "Updated Author"

    assert article.title == "Updated"
    assert article.content == "Updated Content"
    assert article.author == "Updated Author"


# ============================================================================
# Tests for CharField - Constructor Parameter Validation
# ============================================================================


def test_charfield_requires_max_length_parameter():
    """Test CharField requires max_length parameter."""
    with pytest.raises(TypeError):

        class TestModel(Model):
            name = CharField()  # Missing max_length


def test_charfield_accepts_all_parameters():
    """Test CharField accepts all valid parameters."""

    class TestModel(Model):
        field = CharField(
            max_length=100, default="default_value", unique=True, nullable=False
        )

    assert TestModel.field.max_length == 100
    assert TestModel.field.default == "default_value"
    assert TestModel.field.unique is True
    assert TestModel.field.nullable is False


def test_textfield_accepts_standard_parameters():
    """Test TextField accepts standard Field parameters."""

    class TestModel(Model):
        field = TextField(default="default_content", unique=False, nullable=True)

    assert TestModel.field.default == "default_content"
    assert TestModel.field.unique is False
    assert TestModel.field.nullable is True
