"""
Comprehensive test suite for Redshift UNLOAD configuration.

This test class validates the UnloadConfig dataclass and its methods
for building S3 paths and UNLOAD queries.

Note: These tests require the full data-exchange-agent environment to be
properly configured with all dependencies including the shared module.
"""

import pytest

# Check if required modules are available
try:
    from data_exchange_agent.config.sections.connections.odbc.redshift import UnloadConfig

    UNLOAD_CONFIG_AVAILABLE = True
except ImportError:
    UNLOAD_CONFIG_AVAILABLE = False
    UnloadConfig = None


pytestmark = pytest.mark.skipif(
    not UNLOAD_CONFIG_AVAILABLE,
    reason="UnloadConfig not available (missing shared module dependencies)",
)


class TestUnloadConfigDefaults:
    """
    Test suite for UnloadConfig default values.

    Validates that UnloadConfig has correct default values for optional fields.
    """

    def test_default_file_format_is_parquet(self):
        """Test that default file format is 'parquet'."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        assert config.file_format == "parquet"

    def test_default_max_file_size_is_256(self):
        """Test that default max file size is 256 MB."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        assert config.max_file_size_mb == 256

    def test_default_s3_prefix_is_none(self):
        """Test that default S3 prefix is None."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        assert config.s3_prefix is None

    def test_custom_file_format(self):
        """Test setting custom file format."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
            file_format="csv",
        )
        assert config.file_format == "csv"

    def test_custom_max_file_size(self):
        """Test setting custom max file size."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
            max_file_size_mb=512,
        )
        assert config.max_file_size_mb == 512


class TestUnloadConfigBuildS3Path:
    """
    Test suite for UnloadConfig.build_s3_path method.

    Validates the construction of full S3 paths from relative paths.
    """

    def test_build_s3_path_without_prefix(self):
        """Test building S3 path without an S3 prefix."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        relative_path = "workflows/1/tables/2/partition_0"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/workflows/1/tables/2/partition_0/"

    def test_build_s3_path_with_prefix(self):
        """Test building S3 path with an S3 prefix."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
            s3_prefix="data-migration/prod",
        )
        relative_path = "workflows/1/tables/2/partition_0"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/data-migration/prod/workflows/1/tables/2/partition_0/"

    def test_build_s3_path_handles_trailing_slash_in_bucket(self):
        """Test that trailing slashes in bucket name are handled."""
        config = UnloadConfig(
            s3_bucket="my-bucket/",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        relative_path = "path/to/data"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/path/to/data/"

    def test_build_s3_path_handles_leading_slash_in_relative_path(self):
        """Test that leading slashes in relative path are handled."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        relative_path = "/workflows/1/data/"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/workflows/1/data/"

    def test_build_s3_path_handles_trailing_slash_in_relative_path(self):
        """Test that trailing slashes in relative path are handled."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        relative_path = "workflows/1/data/"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/workflows/1/data/"

    def test_build_s3_path_handles_slashes_in_prefix(self):
        """Test that slashes in S3 prefix are handled correctly."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
            s3_prefix="/data-migration/prod/",
        )
        relative_path = "workflows/1/data"
        result = config.build_s3_path(relative_path)

        assert result == "s3://my-bucket/data-migration/prod/workflows/1/data/"

    def test_build_s3_path_with_simple_relative_path(self):
        """Test building S3 path with a simple single-segment relative path."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        result = config.build_s3_path("output")

        assert result == "s3://bucket/output/"


class TestUnloadConfigBuildUnloadQuery:
    """
    Test suite for UnloadConfig.build_unload_query method.

    Validates the construction of UNLOAD SQL statements.
    """

    def test_build_unload_query_parquet_format(self):
        """Test building UNLOAD query with Parquet format."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123456789012:role/RedshiftRole",
            file_format="parquet",
            max_file_size_mb=256,
        )
        select_query = "SELECT * FROM users"
        s3_path = "s3://my-bucket/exports/users/"

        result = config.build_unload_query(select_query, s3_path)

        assert "UNLOAD ('SELECT * FROM users')" in result
        assert "TO 's3://my-bucket/exports/users/'" in result
        assert "IAM_ROLE 'arn:aws:iam::123456789012:role/RedshiftRole'" in result
        assert "FORMAT AS PARQUET" in result
        assert "ALLOWOVERWRITE" in result
        assert "PARALLEL ON" in result
        assert "MAXFILESIZE 256 MB" in result

    def test_build_unload_query_csv_format(self):
        """Test building UNLOAD query with CSV format."""
        config = UnloadConfig(
            s3_bucket="my-bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
            file_format="csv",
            max_file_size_mb=128,
        )
        select_query = "SELECT id, name FROM users"
        s3_path = "s3://my-bucket/exports/users/"

        result = config.build_unload_query(select_query, s3_path)

        assert "UNLOAD ('SELECT id, name FROM users')" in result
        assert "FORMAT AS CSV DELIMITER ',' ADDQUOTES HEADER" in result
        assert "MAXFILESIZE 128 MB" in result

    def test_build_unload_query_escapes_single_quotes(self):
        """Test that single quotes in SELECT query are properly escaped."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        select_query = "SELECT * FROM users WHERE name = 'John'"
        s3_path = "s3://bucket/output/"

        result = config.build_unload_query(select_query, s3_path)

        # Single quotes should be escaped (doubled) inside the UNLOAD
        assert "name = ''John''" in result

    def test_build_unload_query_with_complex_select(self):
        """Test building UNLOAD query with a complex SELECT statement."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        select_query = """
            SELECT
                u.id,
                u.name,
                COUNT(o.id) as order_count
            FROM users u
            LEFT JOIN orders o ON u.id = o.user_id
            WHERE u.status = 'active'
            GROUP BY u.id, u.name
            HAVING COUNT(o.id) > 0
        """
        s3_path = "s3://bucket/output/"

        result = config.build_unload_query(select_query, s3_path)

        assert "SELECT" in result
        assert "FROM users u" in result
        assert "LEFT JOIN orders o" in result
        assert "status = ''active''" in result

    def test_build_unload_query_with_different_max_file_sizes(self):
        """Test UNLOAD query with various max file sizes."""
        for size in [64, 128, 256, 512, 1024]:
            config = UnloadConfig(
                s3_bucket="bucket",
                iam_role_arn="arn:aws:iam::123:role/Role",
                max_file_size_mb=size,
            )
            result = config.build_unload_query("SELECT 1", "s3://bucket/path/")
            assert f"MAXFILESIZE {size} MB" in result


class TestUnloadConfigIntegration:
    """
    Integration tests for UnloadConfig.

    Validates the complete workflow of building S3 paths and UNLOAD queries.
    """

    def test_end_to_end_unload_generation(self):
        """Test complete UNLOAD command generation workflow."""
        config = UnloadConfig(
            s3_bucket="production-data-lake",
            iam_role_arn="arn:aws:iam::123456789012:role/RedshiftUnloadRole",
            s3_prefix="data-migration/dmv-blue",
            file_format="parquet",
            max_file_size_mb=256,
        )

        # Simulate orchestrator's relative path
        relative_path = "workflows/42/tables/123/data/partition_0"

        # Build S3 path
        s3_path = config.build_s3_path(relative_path)
        assert s3_path == "s3://production-data-lake/data-migration/dmv-blue/workflows/42/tables/123/data/partition_0/"

        # Build UNLOAD query
        select_query = "SELECT * FROM schema.my_table WHERE batch_id = 1"
        unload_query = config.build_unload_query(select_query, s3_path)

        # Verify the complete UNLOAD statement
        assert "UNLOAD" in unload_query
        assert s3_path in unload_query
        assert "IAM_ROLE 'arn:aws:iam::123456789012:role/RedshiftUnloadRole'" in unload_query
        assert "FORMAT AS PARQUET" in unload_query

    def test_csv_export_workflow(self):
        """Test CSV export workflow for compatibility scenarios."""
        config = UnloadConfig(
            s3_bucket="exports",
            iam_role_arn="arn:aws:iam::999:role/ExportRole",
            file_format="csv",
            max_file_size_mb=64,
        )

        s3_path = config.build_s3_path("daily/2024-01-15")
        unload_query = config.build_unload_query("SELECT * FROM events", s3_path)

        assert "FORMAT AS CSV" in unload_query
        assert "DELIMITER ','" in unload_query
        assert "ADDQUOTES" in unload_query
        assert "HEADER" in unload_query


class TestUnloadConfigEdgeCases:
    """
    Test suite for edge cases in UnloadConfig.

    Validates handling of unusual inputs and boundary conditions.
    """

    def test_empty_relative_path(self):
        """Test building S3 path with empty relative path."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        result = config.build_s3_path("")

        assert result == "s3://bucket//"

    def test_relative_path_with_only_slashes(self):
        """Test building S3 path with relative path containing only slashes."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        result = config.build_s3_path("///")

        assert result == "s3://bucket//"

    def test_select_query_with_multiple_single_quotes(self):
        """Test UNLOAD query with multiple single quotes in SELECT."""
        config = UnloadConfig(
            s3_bucket="bucket",
            iam_role_arn="arn:aws:iam::123:role/Role",
        )
        select_query = "SELECT * FROM users WHERE name IN ('Alice', 'Bob', 'O''Brien')"
        result = config.build_unload_query(select_query, "s3://bucket/path/")

        # All single quotes should be doubled
        assert "''Alice''" in result
        assert "''Bob''" in result
        # O'Brien already has one escape, should become O'''Brien
        assert "O''''Brien" in result
