"""
Test for DROP operations bug fix

Verifies that DROP operations (catalog, schema, table) are properly handled
during rollback and SQL generation, not batched with CREATE/ALTER operations.

Bug: DROP operations were being batched but then skipped because the batch
processor expected CREATE operations. This caused 0 SQL statements to be
generated for rollback operations like drop_schema.
"""

from schemax.providers.unity.models import UnityState
from schemax.providers.unity.sql_generator import UnitySQLGenerator
from tests.utils.operation_builders import OperationBuilder


def test_drop_schema_generates_sql() -> None:
    """Test that drop_schema operation generates SQL correctly during rollback"""
    # Scenario: Rollback from v0.2.0 to v0.1.0 after adding product_360 schema
    # The state differ generates a drop_schema operation

    # Create state with BOTH schemas (v0.2.0 state - before rollback)
    # This is the state used for SQL generation
    state = UnityState(
        catalogs=[
            {
                "id": "cat_1",
                "name": "sales_analytics",
                "schemas": [
                    {
                        "id": "sch_customer",
                        "name": "customer_360",
                        "tables": [],
                    },
                    {
                        "id": "sch_product",
                        "name": "product_360",
                        "tables": [],
                    },
                ],
            }
        ]
    )

    # Operation to drop product_360 schema (generated by state differ during rollback)
    builder = OperationBuilder()
    drop_schema_op = builder.drop_schema("sch_product")

    # Generate SQL with catalog mapping (dev environment)
    generator = UnitySQLGenerator(
        state,
        catalog_name_mapping={"sales_analytics": "dev_sales_analytics"},
        environment_name="dev",
    )

    result = generator.generate_sql_with_mapping([drop_schema_op])

    # Verify SQL was generated (not empty!)
    assert result.sql, "DROP SCHEMA operation should generate SQL"
    assert len(result.statements) == 1, "Should have 1 statement"

    # Verify the SQL is correct
    sql = result.statements[0].sql
    assert "DROP SCHEMA IF EXISTS" in sql
    assert "dev_sales_analytics" in sql  # Physical catalog name
    assert "product_360" in sql

    # Verify operation tracking
    assert drop_schema_op.id in result.statements[0].operation_ids


def test_drop_catalog_generates_sql() -> None:
    """Test that drop_catalog operation generates SQL correctly"""
    # State includes the catalog that will be dropped
    state = UnityState(
        catalogs=[
            {
                "id": "cat_test",
                "name": "test_catalog",
                "schemas": [],
            }
        ]
    )

    builder = OperationBuilder()
    drop_catalog_op = builder.drop_catalog("cat_test")

    generator = UnitySQLGenerator(
        state,
        catalog_name_mapping={"test_catalog": "dev_test_catalog"},
        environment_name="dev",
    )

    result = generator.generate_sql_with_mapping([drop_catalog_op])

    # Verify SQL was generated
    assert result.sql
    assert len(result.statements) == 1
    assert "DROP CATALOG IF EXISTS" in result.statements[0].sql
    assert "dev_test_catalog" in result.statements[0].sql


def test_drop_table_generates_sql() -> None:
    """Test that drop_table operation generates SQL correctly"""
    # State includes the table that will be dropped
    state = UnityState(
        catalogs=[
            {
                "id": "cat_1",
                "name": "sales_analytics",
                "schemas": [
                    {
                        "id": "sch_1",
                        "name": "customer_360",
                        "tables": [
                            {
                                "id": "tbl_customer",
                                "name": "customer",
                                "format": "delta",
                                "columns": [],
                            }
                        ],
                    }
                ],
            }
        ]
    )

    # Drop table operation (state differ creates with empty payload)
    builder = OperationBuilder()
    drop_table_op = builder.drop_table("tbl_customer")

    generator = UnitySQLGenerator(
        state,
        catalog_name_mapping={"sales_analytics": "dev_sales_analytics"},
        environment_name="dev",
    )

    result = generator.generate_sql_with_mapping([drop_table_op])

    # Verify SQL was generated
    assert result.sql
    assert len(result.statements) == 1
    sql = result.statements[0].sql
    assert "DROP TABLE IF EXISTS" in sql
    assert "dev_sales_analytics" in sql
    assert "customer_360" in sql
    assert "customer" in sql


def test_multiple_drop_operations_different_objects() -> None:
    """Test multiple DROP operations on different objects generate correct SQL"""
    # State includes both objects to be dropped
    state = UnityState(
        catalogs=[
            {
                "id": "cat_1",
                "name": "analytics",
                "schemas": [
                    {
                        "id": "sch_1",
                        "name": "sales",
                        "tables": [
                            {
                                "id": "tbl_orders",
                                "name": "orders",
                                "format": "delta",
                                "columns": [],
                            }
                        ],
                    },
                    {
                        "id": "sch_product",
                        "name": "products",
                        "tables": [],
                    },
                ],
            }
        ]
    )

    # Drop table and schema
    builder = OperationBuilder()
    drop_table_op = builder.drop_table("tbl_orders")
    drop_schema_op = builder.drop_schema("sch_product")

    generator = UnitySQLGenerator(state, environment_name="dev")

    result = generator.generate_sql_with_mapping([drop_table_op, drop_schema_op])

    # Verify both statements generated
    assert len(result.statements) == 2

    # Verify order: table drops before schema drops (reverse dependency order)
    # Table has dependency level 2, schema has level 1
    # We sort by -dependency_level, so table (level 2) comes first
    first_sql = result.statements[0].sql
    second_sql = result.statements[1].sql

    assert "DROP TABLE" in first_sql
    assert "DROP SCHEMA" in second_sql


def test_drop_operations_not_batched_with_create() -> None:
    """Test that DROP operations are not batched with CREATE operations"""
    # State includes the old schema to drop, but not the new one
    state = UnityState(
        catalogs=[
            {
                "id": "cat_1",
                "name": "analytics",
                "schemas": [
                    {
                        "id": "sch_old",
                        "name": "old_schema",
                        "tables": [],
                    }
                ],
            }
        ]
    )

    # Create and drop different schemas (should not cancel or batch)
    builder = OperationBuilder()
    add_schema_op = builder.add_schema("sch_new", "new_schema", "cat_1")
    drop_schema_op = builder.drop_schema("sch_old")

    generator = UnitySQLGenerator(state, environment_name="dev")

    result = generator.generate_sql_with_mapping([add_schema_op, drop_schema_op])

    # Both operations should generate SQL
    assert len(result.statements) == 2

    # Verify CREATE comes before DROP (dependency order)
    assert "CREATE SCHEMA" in result.statements[0].sql
    assert "DROP SCHEMA" in result.statements[1].sql


def test_rollback_scenario_v0_2_to_v0_1() -> None:
    """
    Integration test for the exact bug scenario reported:
    Rolling back from v0.2.0 to v0.1.0 where product_360 schema was added.

    v0.1.0: sales_analytics catalog + customer_360 schema
    v0.2.0: + product_360 schema + product table
    Rollback: Drop product table, then drop product_360 schema

    KEY: SQL generation uses v0.2.0 state (with objects to drop), not v0.1.0 state!
    """
    # State at v0.2.0 (CURRENT state before rollback - includes objects to drop)
    state_v0_2_0 = UnityState(
        catalogs=[
            {
                "id": "cat_sales",
                "name": "sales_analytics",
                "schemas": [
                    {
                        "id": "sch_customer",
                        "name": "customer_360",
                        "tables": [
                            {
                                "id": "tbl_customer",
                                "name": "customer",
                                "format": "delta",
                                "columns": [
                                    {
                                        "id": "col_cid",
                                        "name": "cid",
                                        "type": "INT",
                                        "nullable": False,
                                    },
                                    {
                                        "id": "col_cname",
                                        "name": "cname",
                                        "type": "STRING",
                                        "nullable": True,
                                    },
                                ],
                            }
                        ],
                    },
                    {
                        "id": "sch_product",
                        "name": "product_360",
                        "tables": [
                            {
                                "id": "tbl_product",
                                "name": "product",
                                "format": "delta",
                                "columns": [
                                    {
                                        "id": "col_pid",
                                        "name": "pid",
                                        "type": "STRING",
                                        "nullable": True,
                                    },
                                    {
                                        "id": "col_pname",
                                        "name": "pname",
                                        "type": "STRING",
                                        "nullable": True,
                                    },
                                ],
                            }
                        ],
                    },
                ],
            }
        ]
    )

    # Operations generated by state differ for rollback (v0.2.0 → v0.1.0)
    # These would be generated by UnityStateDiffer.generate_diff_operations()
    builder = OperationBuilder()
    rollback_ops = [
        # First drop the table in product_360 schema
        builder.drop_table("tbl_product"),
        # Then drop the product_360 schema
        builder.drop_schema("sch_product"),
    ]

    # Generate SQL for dev environment using v0.2.0 state
    generator = UnitySQLGenerator(
        state_v0_2_0,
        catalog_name_mapping={"sales_analytics": "dev_sales_analytics"},
        environment_name="dev",
    )

    result = generator.generate_sql_with_mapping(rollback_ops)

    # THIS WAS THE BUG: SQL was empty (0 statements)!
    # After fix: Should have 2 statements
    assert result.sql, "Rollback SQL should not be empty!"
    assert len(result.statements) == 2, "Should have 2 rollback statements"

    # Verify DROP TABLE comes first (dependency order)
    drop_table_sql = result.statements[0].sql
    drop_schema_sql = result.statements[1].sql

    assert "DROP TABLE IF EXISTS" in drop_table_sql
    assert "dev_sales_analytics" in drop_table_sql
    assert "product_360" in drop_table_sql
    assert "product" in drop_table_sql

    assert "DROP SCHEMA IF EXISTS" in drop_schema_sql
    assert "dev_sales_analytics" in drop_schema_sql
    assert "product_360" in drop_schema_sql

    # Verify operation tracking
    assert rollback_ops[0].id in result.statements[0].operation_ids
    assert rollback_ops[1].id in result.statements[1].operation_ids

    print(f"\n{'=' * 60}")
    print("✓ Rollback SQL Generated Successfully!")
    print(f"{'=' * 60}")
    print("\nStatement 1/2 (DROP TABLE):")
    print(drop_table_sql)
    print("\nStatement 2/2 (DROP SCHEMA):")
    print(drop_schema_sql)
    print(f"\n{'=' * 60}")
