"""Step definitions for streamed change models coverage tests."""

from behave import given, then, when

from cleveragents.domain.models.streamedchange.streamed_change import (
    StreamedChangeSection,
    StreamedChangeWithLineNums,
)


@given("I import the StreamedChangeSection class")
def step_import_streamed_change_section(context):
    """Import StreamedChangeSection class."""
    context.model_class = StreamedChangeSection
    context.error = None
    context.instance = None


@given("I import the StreamedChangeWithLineNums class")
def step_import_streamed_change_with_line_nums(context):
    """Import StreamedChangeWithLineNums class."""
    context.model_class = StreamedChangeWithLineNums
    context.error = None
    context.instance = None


@when("I create a StreamedChangeSection with start_line {line:d}")
def step_create_section_with_start_line(context, line):
    """Create StreamedChangeSection with start_line."""
    context.start_line = line
    context.end_line = None
    context.start_line_string = None
    context.end_line_string = None


@when("I set end_line to {line:d}")
def step_set_end_line(context, line):
    """Set end_line field."""
    context.end_line = line


@when('I set start_line_string to "{text}"')
def step_set_start_line_string(context, text):
    """Set start_line_string field."""
    context.start_line_string = text


@when('I set end_line_string to "{text}"')
def step_set_end_line_string(context, text):
    """Set end_line_string field."""
    context.end_line_string = text
    # Create the instance now that all fields are set
    if hasattr(context, "start_line"):
        try:
            context.instance = StreamedChangeSection(
                start_line=context.start_line,
                end_line=context.end_line,
                start_line_string=context.start_line_string,
                end_line_string=context.end_line_string,
            )
        except Exception as e:
            context.error = e


@then("the StreamedChangeSection instance should be created successfully")
def step_section_created_successfully(context):
    """Verify StreamedChangeSection instance was created."""
    assert context.instance is not None, (
        "StreamedChangeSection instance was not created"
    )
    assert isinstance(context.instance, StreamedChangeSection), (
        "Instance is not StreamedChangeSection"
    )
    assert context.error is None, f"Unexpected error: {context.error}"


@then("the start_line should be {line:d}")
def step_verify_start_line(context, line):
    """Verify the start_line value."""
    assert context.instance.start_line == line, (
        f"Expected start_line {line}, got {context.instance.start_line}"
    )


@then("the end_line should be {line:d}")
def step_verify_end_line(context, line):
    """Verify the end_line value."""
    assert context.instance.end_line == line, (
        f"Expected end_line {line}, got {context.instance.end_line}"
    )


@then('the start_line_string should be "{text}"')
def step_verify_start_line_string(context, text):
    """Verify the start_line_string value."""
    assert context.instance.start_line_string == text, (
        f"Expected start_line_string '{text}', got '{context.instance.start_line_string}'"
    )


@then('the end_line_string should be "{text}"')
def step_verify_end_line_string(context, text):
    """Verify the end_line_string value."""
    assert context.instance.end_line_string == text, (
        f"Expected end_line_string '{text}', got '{context.instance.end_line_string}'"
    )


@when("I create a StreamedChangeSection using aliases")
def step_create_section_using_aliases(context):
    """Create StreamedChangeSection using field aliases."""
    try:
        context.instance = StreamedChangeSection(
            startLine=15,
            endLine=25,
            startLineString="function start",
            endLineString="function end",
        )
        context.error = None
    except Exception as e:
        context.error = e


@then("the StreamedChangeSection should accept the aliased fields")
def step_section_accepts_aliases(context):
    """Verify StreamedChangeSection accepts aliased fields."""
    assert context.instance is not None
    assert context.error is None


@then("the section values should be properly mapped")
def step_section_values_mapped(context):
    """Verify section values are properly mapped."""
    assert context.instance.start_line == 15
    assert context.instance.end_line == 25
    assert context.instance.start_line_string == "function start"
    assert context.instance.end_line_string == "function end"


@when("I create a StreamedChangeSection with valid data")
def step_create_section_with_valid_data(context):
    """Create StreamedChangeSection with valid data for configuration testing."""
    context.instance = StreamedChangeSection(
        start_line=1, end_line=10, start_line_string="start", end_line_string="end"
    )


@then("the section configuration should have str_strip_whitespace as {value}")
def step_verify_section_str_strip_whitespace(context, value):
    """Verify section str_strip_whitespace configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["str_strip_whitespace"] == expected


@then("the section configuration should have validate_assignment as {value}")
def step_verify_section_validate_assignment(context, value):
    """Verify section validate_assignment configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["validate_assignment"] == expected


@then("the section configuration should have arbitrary_types_allowed as {value}")
def step_verify_section_arbitrary_types_allowed(context, value):
    """Verify section arbitrary_types_allowed configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["arbitrary_types_allowed"] == expected


@then("the section configuration should have populate_by_name as {value}")
def step_verify_section_populate_by_name(context, value):
    """Verify section populate_by_name configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["populate_by_name"] == expected


@then("the section configuration should have use_enum_values as {value}")
def step_verify_section_use_enum_values(context, value):
    """Verify section use_enum_values configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["use_enum_values"] == expected


@given("I have a valid StreamedChangeSection for old section")
def step_create_valid_section_for_old(context):
    """Create a valid StreamedChangeSection for use as old section."""
    context.old_section = StreamedChangeSection(
        start_line=10,
        end_line=20,
        start_line_string="def old_function():",
        end_line_string="    return old_value",
    )


@when("I create a StreamedChangeWithLineNums with the old section")
def step_create_change_with_old_section(context):
    """Create StreamedChangeWithLineNums with old section."""
    context.old = context.old_section
    context.start_line_included = None
    context.end_line_included = None
    context.new = None


@when("I set start_line_included to {value}")
def step_set_start_line_included(context, value):
    """Set start_line_included field."""
    context.start_line_included = value.lower() == "true"


@when("I set end_line_included to {value}")
def step_set_end_line_included(context, value):
    """Set end_line_included field."""
    context.end_line_included = value.lower() == "true"


@when('I set new content to "{text}"')
def step_set_new_content(context, text):
    """Set new content field."""
    context.new = text
    # Create the instance now that all fields are set
    if hasattr(context, "old"):
        try:
            context.instance = StreamedChangeWithLineNums(
                old=context.old,
                start_line_included=context.start_line_included,
                end_line_included=context.end_line_included,
                new=context.new,
            )
        except Exception as e:
            context.error = e


@when('I set new content to ""')
def step_set_empty_new_content(context):
    """Set new content to empty string."""
    context.new = ""
    # Create the instance now that all fields are set
    if hasattr(context, "old"):
        try:
            context.instance = StreamedChangeWithLineNums(
                old=context.old,
                start_line_included=context.start_line_included,
                end_line_included=context.end_line_included,
                new=context.new,
            )
        except Exception as e:
            context.error = e


@then("the StreamedChangeWithLineNums instance should be created successfully")
def step_change_created_successfully(context):
    """Verify StreamedChangeWithLineNums instance was created."""
    assert context.instance is not None, (
        "StreamedChangeWithLineNums instance was not created"
    )
    assert isinstance(context.instance, StreamedChangeWithLineNums), (
        "Instance is not StreamedChangeWithLineNums"
    )
    assert context.error is None, f"Unexpected error: {context.error}"


@then("the old section should match the provided section")
def step_verify_old_section(context):
    """Verify the old section matches."""
    assert context.instance.old == context.old_section


@then("the start_line_included should be {value}")
def step_verify_start_line_included(context, value):
    """Verify start_line_included value."""
    expected = value.lower() == "true"
    assert context.instance.start_line_included == expected


@then("the end_line_included should be {value}")
def step_verify_end_line_included(context, value):
    """Verify end_line_included value."""
    expected = value.lower() == "true"
    assert context.instance.end_line_included == expected


@then('the new content should be "{text}"')
def step_verify_new_content(context, text):
    """Verify new content value."""
    assert context.instance.new == text


@then('the new content should be ""')
def step_verify_empty_new_content(context):
    """Verify new content is empty."""
    assert context.instance.new == ""


@when("I set new content to multiline text")
def step_set_multiline_new_content(context):
    """Set new content to multiline text."""
    context.new = """def new_function():
    # This is a new implementation
    value = compute_value()
    return value * 2"""
    # Create the instance
    if hasattr(context, "old"):
        try:
            context.instance = StreamedChangeWithLineNums(
                old=context.old,
                start_line_included=context.start_line_included,
                end_line_included=context.end_line_included,
                new=context.new,
            )
        except Exception as e:
            context.error = e


@then("the new content should contain multiple lines")
def step_verify_multiline_content(context):
    """Verify new content contains multiple lines."""
    assert "\n" in context.instance.new
    assert len(context.instance.new.split("\n")) > 1


@when("I create a StreamedChangeWithLineNums using aliases")
def step_create_change_using_aliases(context):
    """Create StreamedChangeWithLineNums using field aliases."""
    try:
        context.instance = StreamedChangeWithLineNums(
            old=context.old_section,
            startLineIncluded=True,
            endLineIncluded=False,
            new="replacement text",
        )
        context.error = None
    except Exception as e:
        context.error = e


@then("the StreamedChangeWithLineNums should accept the aliased fields")
def step_change_accepts_aliases(context):
    """Verify StreamedChangeWithLineNums accepts aliased fields."""
    assert context.instance is not None
    assert context.error is None


@then("the change values should be properly mapped")
def step_change_values_mapped(context):
    """Verify change values are properly mapped."""
    assert context.instance.start_line_included is True
    assert context.instance.end_line_included is False
    assert context.instance.new == "replacement text"


@when("I create a StreamedChangeWithLineNums with valid data")
def step_create_change_with_valid_data(context):
    """Create StreamedChangeWithLineNums with valid data for configuration testing."""
    section = StreamedChangeSection(
        start_line=1, end_line=5, start_line_string="start", end_line_string="end"
    )
    context.instance = StreamedChangeWithLineNums(
        old=section, start_line_included=True, end_line_included=True, new="new content"
    )


@then("the change configuration should have str_strip_whitespace as {value}")
def step_verify_change_str_strip_whitespace(context, value):
    """Verify change str_strip_whitespace configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["str_strip_whitespace"] == expected


@then("the change configuration should have validate_assignment as {value}")
def step_verify_change_validate_assignment(context, value):
    """Verify change validate_assignment configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["validate_assignment"] == expected


@then("the change configuration should have arbitrary_types_allowed as {value}")
def step_verify_change_arbitrary_types_allowed(context, value):
    """Verify change arbitrary_types_allowed configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["arbitrary_types_allowed"] == expected


@then("the change configuration should have populate_by_name as {value}")
def step_verify_change_populate_by_name(context, value):
    """Verify change populate_by_name configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["populate_by_name"] == expected


@then("the change configuration should have use_enum_values as {value}")
def step_verify_change_use_enum_values(context, value):
    """Verify change use_enum_values configuration."""
    expected = value.lower() == "true"
    assert context.instance.model_config["use_enum_values"] == expected


@when("I create a StreamedChangeSection with whitespace in strings")
def step_create_section_with_whitespace(context):
    """Create StreamedChangeSection with whitespace in strings."""
    try:
        context.instance = StreamedChangeSection(
            start_line=1,
            end_line=2,
            start_line_string="  trimmed start  ",
            end_line_string="  trimmed end  ",
        )
        context.error = None
    except Exception as e:
        context.error = e


@then("the whitespace should be stripped from string fields")
def step_whitespace_stripped_from_strings(context):
    """Verify whitespace is stripped from string fields."""
    assert context.instance.start_line_string == "trimmed start"
    assert context.instance.end_line_string == "trimmed end"


@then("the section should be created successfully")
def step_section_created_ok(context):
    """Verify section was created successfully."""
    assert context.instance is not None
    assert context.error is None


@when("I create a StreamedChangeWithLineNums with whitespace in new content")
def step_create_change_with_whitespace_new(context):
    """Create StreamedChangeWithLineNums with whitespace in new content."""
    try:
        context.instance = StreamedChangeWithLineNums(
            old=context.old_section,
            start_line_included=True,
            end_line_included=True,
            new="  trimmed new content  ",
        )
        context.error = None
    except Exception as e:
        context.error = e


@then("the whitespace should be stripped from new field")
def step_whitespace_stripped_from_new(context):
    """Verify whitespace is stripped from new field."""
    assert context.instance.new == "trimmed new content"


@then("the change should be created successfully")
def step_change_created_ok(context):
    """Verify change was created successfully."""
    assert context.instance is not None
    assert context.error is None


@when("I create a complex StreamedChangeWithLineNums")
def step_create_complex_change(context):
    """Create a complex StreamedChangeWithLineNums with nested section."""
    nested_section = StreamedChangeSection(
        start_line=100,
        end_line=200,
        start_line_string="class ComplexClass:",
        end_line_string="# End of ComplexClass",
    )
    context.instance = StreamedChangeWithLineNums(
        old=nested_section,
        start_line_included=False,
        end_line_included=True,
        new="# Completely new implementation",
    )


@then("the nested StreamedChangeSection should be accessible")
def step_verify_nested_section(context):
    """Verify nested StreamedChangeSection is accessible."""
    assert context.instance.old is not None
    assert isinstance(context.instance.old, StreamedChangeSection)


@then("all nested fields should be properly initialized")
def step_verify_nested_fields(context):
    """Verify all nested fields are properly initialized."""
    assert context.instance.old.start_line == 100
    assert context.instance.old.end_line == 200
    assert context.instance.old.start_line_string == "class ComplexClass:"
    assert context.instance.old.end_line_string == "# End of ComplexClass"


@when("I create a StreamedChangeSection with special characters")
def step_create_section_with_special_chars(context):
    """Create StreamedChangeSection with special characters."""
    context.instance = StreamedChangeSection(
        start_line=1,
        end_line=2,
        start_line_string="print('Hello, 世界! 🌍')",
        end_line_string="# Comment with émojis 😀 and ñoñ-ASCII",
    )


@then("the special characters should be preserved")
def step_verify_special_chars_preserved(context):
    """Verify special characters are preserved."""
    assert "世界" in context.instance.start_line_string
    assert "🌍" in context.instance.start_line_string
    assert "😀" in context.instance.end_line_string
    assert "ñ" in context.instance.end_line_string


@then("the section should handle unicode properly")
def step_verify_unicode_handling(context):
    """Verify section handles unicode properly."""
    assert context.instance is not None
    # Verify the strings are properly stored
    assert len(context.instance.start_line_string) > 0
    assert len(context.instance.end_line_string) > 0


@when("I create a StreamedChangeSection with different field types")
def step_create_section_with_different_types(context):
    """Create StreamedChangeSection to test field types."""
    context.instance = StreamedChangeSection(
        start_line=42,
        end_line=100,
        start_line_string="string value",
        end_line_string="another string",
    )


@then("the integer fields should be validated")
def step_verify_integer_fields(context):
    """Verify integer fields are validated."""
    assert isinstance(context.instance.start_line, int)
    assert isinstance(context.instance.end_line, int)


@then("the string fields should be validated")
def step_verify_string_fields(context):
    """Verify string fields are validated."""
    assert isinstance(context.instance.start_line_string, str)
    assert isinstance(context.instance.end_line_string, str)


@when("I create a StreamedChangeWithLineNums with different field types")
def step_create_change_with_different_types(context):
    """Create StreamedChangeWithLineNums to test field types."""
    context.instance = StreamedChangeWithLineNums(
        old=context.old_section,
        start_line_included=True,
        end_line_included=False,
        new="test string",
    )


@then("the boolean fields should be validated")
def step_verify_boolean_fields(context):
    """Verify boolean fields are validated."""
    assert isinstance(context.instance.start_line_included, bool)
    assert isinstance(context.instance.end_line_included, bool)


@then("the nested object should be validated")
def step_verify_nested_object(context):
    """Verify nested object is validated."""
    assert isinstance(context.instance.old, StreamedChangeSection)
    assert isinstance(context.instance.new, str)


@given("I have a StreamedChangeSection representing lines to delete")
def step_create_section_for_deletion(context):
    """Create a StreamedChangeSection representing lines to delete."""
    context.deletion_section = StreamedChangeSection(
        start_line=50,
        end_line=60,
        start_line_string="# Old code to remove",
        end_line_string="# End of old code",
    )


@when("I create a StreamedChangeWithLineNums for deletion")
def step_create_change_for_deletion(context):
    """Create StreamedChangeWithLineNums for deletion."""
    context.old = context.deletion_section
    context.start_line_included = None
    context.end_line_included = None
    context.new = None


@then("the StreamedChangeWithLineNums instance should represent a deletion")
def step_verify_deletion_representation(context):
    """Verify the instance represents a deletion."""
    assert context.instance.new == ""
    assert context.instance.start_line_included is True
    assert context.instance.end_line_included is True


@then("the old section should contain the deleted content")
def step_verify_deleted_content(context):
    """Verify old section contains the deleted content."""
    assert context.instance.old.start_line == 50
    assert context.instance.old.end_line == 60
    assert "Old code to remove" in context.instance.old.start_line_string
