"""Comprehensive test for enhanced SQL public API implementation in duckalog.

This test suite validates that the enhanced SQL public API works correctly,
ensuring all SQL functionality is accessible through multiple import patterns
while maintaining backward compatibility.
"""

from __future__ import annotations

import tempfile
from pathlib import Path

import pytest


# Test 1: Direct SQL imports work correctly
def test_direct_sql_imports():
    """Test that all SQL-related imports work directly from main package."""
    try:
        import duckalog

        # Test SQL generation imports
        assert hasattr(duckalog, "generate_view_sql")
        assert hasattr(duckalog, "generate_all_views_sql")
        assert hasattr(duckalog, "generate_secret_sql")
        assert callable(duckalog.generate_view_sql)
        assert callable(duckalog.generate_all_views_sql)
        assert callable(duckalog.generate_secret_sql)

        # Test SQL utility imports
        assert hasattr(duckalog, "quote_ident")
        assert hasattr(duckalog, "quote_literal")
        assert hasattr(duckalog, "render_options")
        assert callable(duckalog.quote_ident)
        assert callable(duckalog.quote_literal)
        assert callable(duckalog.render_options)

        # Test SQL file loading imports
        assert hasattr(duckalog, "SQLFileLoader")
        assert duckalog.SQLFileLoader is not None

    except ImportError as e:
        pytest.fail(f"Direct SQL imports failed: {e}")


# Test 2: SQL convenience class provides unified access
def test_sql_convenience_class_structure():
    """Test that SQL convenience class provides unified access to all SQL functionality."""
    try:
        import duckalog

        # Check SQL class exists
        assert hasattr(duckalog, "SQLGroup")
        assert duckalog.SQLGroup is not None

        # Check SQL class has expected attributes
        sql_class = duckalog.SQLGroup
        assert hasattr(sql_class, "generate")
        assert hasattr(sql_class, "utils")
        assert hasattr(sql_class, "files")

        # Check that generate module has expected functions
        assert hasattr(sql_class.generate, "generate_view_sql")
        assert hasattr(sql_class.generate, "generate_all_views_sql")
        assert hasattr(sql_class.generate, "generate_secret_sql")

        # Check that utils module has expected functions
        assert hasattr(sql_class.utils, "quote_ident")
        assert hasattr(sql_class.utils, "quote_literal")
        assert hasattr(sql_class.utils, "render_options")

        # Check that files module has SQLFileLoader
        assert hasattr(sql_class.files, "SQLFileLoader")

    except Exception as e:
        pytest.fail(f"SQL convenience class structure test failed: {e}")


# Test 3: Backward compatibility maintained
def test_backward_compatibility_imports():
    """Test that backward compatibility is maintained for existing import patterns."""
    try:
        import duckalog

        # Test old import patterns still work
        assert hasattr(duckalog, "sql")
        assert hasattr(duckalog, "utils")
        assert hasattr(duckalog, "sql_files")

        # Verify they are the same objects as referenced in SQL class
        assert duckalog.sql is duckalog.SQLGroup.generate
        assert duckalog.utils is duckalog.SQLGroup.utils
        assert duckalog.sql_files is duckalog.SQLGroup.files

        # Test they have expected attributes
        assert hasattr(duckalog.sql, "generate_view_sql")
        assert hasattr(duckalog.utils, "quote_ident")
        assert hasattr(duckalog.sql_files, "SQLFileLoader")

    except Exception as e:
        pytest.fail(f"Backward compatibility test failed: {e}")


# Test 4: SQL generation functions accessible and functional
def test_sql_generation_functionality():
    """Test that SQL generation functions are accessible and work correctly."""
    try:
        import duckalog
        from duckalog import ViewConfig, SecretConfig

        # Test generate_view_sql
        view = ViewConfig(
            name="test_view", source="parquet", uri="s3://bucket/test.parquet"
        )
        sql = duckalog.generate_view_sql(view)
        assert "CREATE OR REPLACE VIEW" in sql
        assert "parquet_scan" in sql
        assert "s3://bucket/test.parquet" in sql

        # Test generate_all_views_sql
        from duckalog import Config, DuckDBConfig

        config = Config(version=1, duckdb=DuckDBConfig(), views=[view])
        all_sql = duckalog.generate_all_views_sql(config)
        assert "-- Generated by Duckalog" in all_sql
        assert "-- Config version: 1" in all_sql
        assert sql in all_sql

        # Test generate_secret_sql
        secret = SecretConfig(
            type="s3", name="test_secret", key_id="test_key", secret="test_secret"
        )
        secret_sql = duckalog.generate_secret_sql(secret)
        assert "CREATE SECRET test_secret" in secret_sql
        assert "TYPE S3" in secret_sql
        assert "KEY_ID 'test_key'" in secret_sql

    except Exception as e:
        pytest.fail(f"SQL generation functionality test failed: {e}")


# Test 5: SQL utilities properly exposed and functional
def test_sql_utilities_functionality():
    """Test that SQL utilities are properly exposed and work correctly."""
    try:
        import duckalog

        # Test quote_ident
        quoted_ident = duckalog.quote_ident('test "identifier"')
        assert quoted_ident == '"test ""identifier"""'

        # Test quote_literal
        quoted_literal = duckalog.quote_literal("test'string")
        assert quoted_literal == "'test''string'"

        # Test render_options
        options = {"hive_partitioning": True, "sample_rate": 0.1}
        rendered = duckalog.render_options(options)
        assert "hive_partitioning=TRUE" in rendered
        assert "sample_rate=0.1" in rendered

    except Exception as e:
        pytest.fail(f"SQL utilities functionality test failed: {e}")


# Test 6: SQL file loading functionality works
def test_sql_file_loading_functionality():
    """Test that SQL file loading functionality works correctly."""
    try:
        import duckalog

        # Test SQLFileLoader class is available and functional
        loader = duckalog.SQLFileLoader()
        assert loader is not None

        # Test basic file loading
        with tempfile.TemporaryDirectory() as tmp_dir:
            tmp_path = Path(tmp_dir)
            sql_file = tmp_path / "test.sql"
            sql_file.write_text("SELECT * FROM users")

            config_file = tmp_path / "catalog.yaml"
            config_file.write_text("version: 1")

            result = loader.load_sql_file(
                file_path="test.sql", config_file_path=str(config_file)
            )
            assert result == "SELECT * FROM users"

            # Test template processing
            template_file = tmp_path / "template.sql"
            template_file.write_text(
                "SELECT * FROM {{table}} WHERE active = {{status}}"
            )

            template_result = loader.load_sql_file(
                file_path="template.sql",
                config_file_path=str(config_file),
                variables={"table": "users", "status": True},
                as_template=True,
            )
            assert template_result == "SELECT * FROM users WHERE active = True"

    except Exception as e:
        pytest.fail(f"SQL file loading functionality test failed: {e}")


# Test 7: Mixed import patterns work together
def test_mixed_import_patterns():
    """Test that mixed import patterns work without conflicts."""
    try:
        import duckalog

        # Use direct import
        direct_func = duckalog.quote_ident

        # Use convenience class
        convenience_func = duckalog.SQLGroup.utils.quote_ident

        # Use backward compatible import
        legacy_func = duckalog.utils.quote_ident

        # All should be the same function
        assert direct_func is convenience_func
        assert convenience_func is legacy_func

        # Test they all produce same results
        test_input = 'test "name"'
        expected = '"test ""name"""'

        assert direct_func(test_input) == expected
        assert convenience_func(test_input) == expected
        assert legacy_func(test_input) == expected

    except Exception as e:
        pytest.fail(f"Mixed import patterns test failed: {e}")


# Test 8: Error classes accessible from main package
def test_sql_error_classes_accessibility():
    """Test that SQL-related error classes are accessible from main package."""
    try:
        import duckalog

        # Check that SQL-related error classes are imported
        sql_errors = [
            "SQLFileError",
            "SQLFileNotFoundError",
            "SQLFilePermissionError",
            "SQLFileEncodingError",
            "SQLFileSizeError",
            "SQLTemplateError",
        ]

        for error_class in sql_errors:
            assert hasattr(duckalog, error_class)
            error_cls = getattr(duckalog, error_class)
            assert error_cls is not None
            assert isinstance(error_cls, type)
            assert Exception in error_cls.__mro__

    except Exception as e:
        pytest.fail(f"SQL error classes accessibility test failed: {e}")


# Test 9: SQL convenience class nested access
def test_sql_convenience_class_nested_access():
    """Test that nested access through SQL convenience class works correctly."""
    try:
        import duckalog

        # Test deep nested access
        nested_func = duckalog.SQLGroup.generate.generate_view_sql
        assert nested_func is not None
        assert callable(nested_func)

        # Test that nested access gives same function as direct access
        assert nested_func is duckalog.generate_view_sql

        # Test that it actually works
        from duckalog import ViewConfig

        view = ViewConfig(name="test", sql="SELECT 1")
        result = nested_func(view)
        assert "CREATE OR REPLACE VIEW" in result

    except Exception as e:
        pytest.fail(f"SQL convenience class nested access test failed: {e}")


# Test 10: All exported functions in __all__
def test_sql_functions_in_all_exports():
    """Test that all SQL functions are properly listed in __all__ exports."""
    try:
        import duckalog

        # Check that __all__ exists
        assert hasattr(duckalog, "__all__")
        all_exports = duckalog.__all__
        assert isinstance(all_exports, list)

        # Check that SQL-related exports are included
        sql_exports = [
            "SQLGroup",
            "sql",
            "utils",
            "sql_files",
            "generate_sql",
            "generate_view_sql",
            "generate_all_views_sql",
            "generate_secret_sql",
            "quote_ident",
            "quote_literal",
            "render_options",
            "SQLFileLoader",
        ]

        for export in sql_exports:
            assert export in all_exports, f"{export} not found in __all__ exports"

        # Check that error exports are included
        error_exports = [
            "SQLFileError",
            "SQLFileNotFoundError",
            "SQLFilePermissionError",
            "SQLFileEncodingError",
            "SQLFileSizeError",
            "SQLTemplateError",
        ]

        for export in error_exports:
            assert export in all_exports, f"{export} not found in __all__ exports"

    except Exception as e:
        pytest.fail(f"SQL functions in __all__ exports test failed: {e}")


# Test 11: Function equivalence validation
def test_function_equivalence():
    """Test that all access patterns provide equivalent functions."""
    try:
        import duckalog

        # Test equivalence of generation functions
        assert (
            duckalog.generate_view_sql is duckalog.SQLGroup.generate.generate_view_sql
        )
        assert duckalog.generate_view_sql is duckalog.sql.generate_view_sql

        assert (
            duckalog.generate_all_views_sql
            is duckalog.SQLGroup.generate.generate_all_views_sql
        )
        assert duckalog.generate_all_views_sql is duckalog.sql.generate_all_views_sql

        assert (
            duckalog.generate_secret_sql
            is duckalog.SQLGroup.generate.generate_secret_sql
        )
        assert duckalog.generate_secret_sql is duckalog.sql.generate_secret_sql

        # Test equivalence of utility functions
        assert duckalog.quote_ident is duckalog.SQLGroup.utils.quote_ident
        assert duckalog.quote_ident is duckalog.utils.quote_ident

        assert duckalog.quote_literal is duckalog.SQLGroup.utils.quote_literal
        assert duckalog.quote_literal is duckalog.utils.quote_literal

        assert duckalog.render_options is duckalog.SQLGroup.utils.render_options
        assert duckalog.render_options is duckalog.utils.render_options

        # Test equivalence of file loading
        assert duckalog.SQLFileLoader is duckalog.SQLGroup.files.SQLFileLoader
        assert duckalog.SQLFileLoader is duckalog.sql_files.SQLFileLoader

    except Exception as e:
        pytest.fail(f"Function equivalence validation test failed: {e}")


# Test 12: Real-world usage patterns
def test_real_world_usage_patterns():
    """Test real-world usage patterns to ensure practical functionality."""
    try:
        import duckalog
        from duckalog import ViewConfig, Config, DuckDBConfig

        # Pattern 1: Direct imports (most common)
        view1 = ViewConfig(name="users", source="parquet", uri="data/users.parquet")
        sql1 = duckalog.generate_view_sql(view1)
        assert "CREATE OR REPLACE VIEW" in sql1

        # Pattern 2: Convenience class access (new unified approach)
        view2 = ViewConfig(name="orders", source="delta", uri="data/orders")
        sql2 = duckalog.SQLGroup.generate.generate_view_sql(view2)
        assert "CREATE OR REPLACE VIEW" in sql2

        # Pattern 3: Backward compatible access
        quoted = duckalog.utils.quote_ident("table name")
        assert quoted == '"table name"'

        # Pattern 4: Mixed usage in same code
        config = Config(version=1, duckdb=DuckDBConfig(), views=[view1, view2])

        # Mix direct and convenience class calls
        full_sql = duckalog.SQLGroup.generate.generate_all_views_sql(config)
        individual_sql = duckalog.generate_view_sql(view1)

        assert individual_sql in full_sql
        assert "-- Generated by Duckalog" in full_sql

        # Pattern 5: File loading with convenience class
        with tempfile.TemporaryDirectory() as tmp_dir:
            tmp_path = Path(tmp_dir)
            sql_file = tmp_path / "query.sql"
            sql_file.write_text("SELECT COUNT(*) FROM events")
            config_file = tmp_path / "catalog.yaml"
            config_file.write_text("version: 1")

            loader = duckalog.SQLGroup.files.SQLFileLoader()
            result = loader.load_sql_file("query.sql", str(config_file))
            assert result == "SELECT COUNT(*) FROM events"

    except Exception as e:
        pytest.fail(f"Real-world usage patterns test failed: {e}")
