# tests/test_queryset_delete_postgres.py
"""PostgreSQL-specific tests for QuerySet.delete() method."""

import pytest

from atomsql import Database, Model
from atomsql.orm.fields import BooleanField, CharField, IntegerField, TextField
from atomsql.orm.models import ModelMeta

pytest.importorskip("psycopg")


@pytest.fixture(autouse=True)
def reset_models():
    """Reset model registry before each test."""
    ModelMeta.models.clear()
    yield
    ModelMeta.models.clear()


@pytest.fixture
def postgres_db():
    """Create a PostgreSQL test database."""
    try:
        db = Database(
            "postgresql://atomsql_user:yourpassword@localhost:5432/atomsql_test"
        )

        # Drop all existing tables before starting tests
        tables = db.backend.get_tables()
        if tables:
            for table in tables:
                db.backend.execute(f'DROP TABLE IF EXISTS "{table}" CASCADE')
            db.backend.commit()

        yield db

        # Cleanup after test
        db.close()
    except Exception as e:
        pytest.skip(f"PostgreSQL not available: {e}")


class TestPostgresQuerySetDelete:
    """Test delete with PostgreSQL-specific features."""

    def test_postgres_delete_basic(self, postgres_db):
        """Test basic delete on PostgreSQL."""

        class User(Model):
            name = CharField(max_length=100)
            status = CharField(max_length=50)

        postgres_db.register(User)

        # Create users
        User.bulk_create(
            [
                User(name="Alice", status="active"),
                User(name="Bob", status="inactive"),
                User(name="Charlie", status="active"),
            ]
        )

        # Delete inactive users
        deleted = User.filter(status="inactive").delete()
        assert deleted == 1

        # Verify remaining
        remaining = User.filter().all()
        assert len(remaining) == 2
        for user in remaining:
            assert user.status == "active"

    def test_postgres_delete_multiple_fields(self, postgres_db):
        """Test delete with multiple field filters on PostgreSQL."""

        class Product(Model):
            name = CharField(max_length=100)
            category = CharField(max_length=50)
            price = IntegerField()
            active = BooleanField()

        postgres_db.register(Product)

        Product.bulk_create(
            [
                Product(name="Widget A", category="widgets", price=100, active=True),
                Product(name="Widget B", category="widgets", price=200, active=False),
                Product(name="Gadget A", category="gadgets", price=150, active=True),
                Product(name="Widget C", category="widgets", price=50, active=True),
            ]
        )

        # Delete inactive widgets
        deleted = Product.filter(category="widgets", active=False).delete()
        assert deleted == 1

        # Verify remaining
        remaining = Product.filter().all()
        assert len(remaining) == 3

    def test_postgres_delete_with_transaction_commit(self, postgres_db):
        """Test delete commits properly in PostgreSQL transaction."""

        class Account(Model):
            name = CharField(max_length=100)
            balance = IntegerField()
            closed = BooleanField(default=False)

        postgres_db.register(Account)

        Account.bulk_create(
            [
                Account(name="Account A", balance=0, closed=False),
                Account(name="Account B", balance=100, closed=False),
                Account(name="Account C", balance=0, closed=True),
            ]
        )

        # Delete zero balance accounts in transaction
        with postgres_db.transaction():
            deleted = Account.filter(balance=0).delete()

        assert deleted == 2

        # Verify only Account B remains
        remaining = Account.filter().all()
        assert len(remaining) == 1
        assert remaining[0].name == "Account B"

    def test_postgres_delete_transaction_rollback(self, postgres_db):
        """Test delete rollback on PostgreSQL transaction failure."""

        class Inventory(Model):
            item = CharField(max_length=100)
            quantity = IntegerField()
            expired = BooleanField(default=False)

        postgres_db.register(Inventory)

        Inventory.bulk_create(
            [
                Inventory(item="Apples", quantity=10, expired=False),
                Inventory(item="Bananas", quantity=0, expired=True),
                Inventory(item="Oranges", quantity=5, expired=False),
            ]
        )

        original_count = Inventory.filter().count()

        # Delete in transaction then rollback
        try:
            with postgres_db.transaction():
                deleted = Inventory.filter(expired=True).delete()
                assert deleted == 1
                raise Exception("Force rollback")
        except Exception:
            pass

        # Verify rollback - all items should still exist
        final_count = Inventory.filter().count()
        assert final_count == original_count

    def test_postgres_delete_with_text_field(self, postgres_db):
        """Test delete with TextField on PostgreSQL."""

        class Note(Model):
            title = CharField(max_length=100)
            content = TextField()
            archived = BooleanField(default=False)

        postgres_db.register(Note)

        Note.bulk_create(
            [
                Note(title="Note 1", content="Important content", archived=False),
                Note(title="Note 2", content="Less important", archived=True),
                Note(title="Note 3", content="Very important content", archived=False),
            ]
        )

        # Delete archived notes
        deleted = Note.filter(archived=True).delete()
        assert deleted == 1

        # Verify remaining
        remaining = Note.filter().all()
        assert len(remaining) == 2
        for note in remaining:
            assert note.archived is False

    def test_postgres_delete_large_batch(self, postgres_db):
        """Test delete with large batch on PostgreSQL."""

        class LogEntry(Model):
            message = CharField(max_length=200)
            level = IntegerField()
            processed = BooleanField(default=False)

        postgres_db.register(LogEntry)

        # Create many log entries
        entries = []
        for i in range(200):
            entries.append(
                LogEntry(message=f"Log message {i}", level=i % 5, processed=i % 3 == 0)
            )
        LogEntry.bulk_create(entries)

        # Delete all processed entries
        deleted = LogEntry.filter(processed=True).delete()

        # Should delete roughly 1/3 of entries (every 3rd one)
        expected_deleted = 200 // 3 + (1 if 200 % 3 > 0 else 0)
        assert deleted == expected_deleted

        # Verify remaining
        remaining = LogEntry.filter().count()
        assert remaining == 200 - deleted

    def test_postgres_delete_with_in_operator(self, postgres_db):
        """Test delete with IN operator on PostgreSQL."""

        class Employee(Model):
            name = CharField(max_length=100)
            department = CharField(max_length=50)
            salary = IntegerField()

        postgres_db.register(Employee)

        Employee.bulk_create(
            [
                Employee(name="Alice", department="engineering", salary=100000),
                Employee(name="Bob", department="marketing", salary=80000),
                Employee(name="Charlie", department="engineering", salary=120000),
                Employee(name="David", department="sales", salary=75000),
                Employee(name="Eve", department="marketing", salary=85000),
            ]
        )

        # Delete employees from specific departments
        deleted = Employee.filter(department__in=["marketing", "sales"]).delete()
        assert deleted == 3

        # Verify only engineering employees remain
        remaining = Employee.filter().all()
        assert len(remaining) == 2
        for emp in remaining:
            assert emp.department == "engineering"

    def test_postgres_delete_with_comparison_operators(self, postgres_db):
        """Test delete with comparison operators on PostgreSQL."""

        class Order(Model):
            order_id = CharField(max_length=50)
            amount = IntegerField()
            created_year = IntegerField()

        postgres_db.register(Order)

        Order.bulk_create(
            [
                Order(order_id="ORD001", amount=100, created_year=2023),
                Order(order_id="ORD002", amount=250, created_year=2024),
                Order(order_id="ORD003", amount=50, created_year=2023),
                Order(order_id="ORD004", amount=300, created_year=2024),
            ]
        )

        # Delete orders with amount > 200
        deleted = Order.filter(amount__gt=200).delete()
        assert deleted == 2

        # Verify remaining orders
        remaining = Order.filter().all()
        assert len(remaining) == 2
        for order in remaining:
            assert order.amount <= 200

    def test_postgres_delete_return_count_accuracy(self, postgres_db):
        """Test that PostgreSQL delete returns accurate count."""

        class Task(Model):
            title = CharField(max_length=100)
            completed = BooleanField(default=False)
            priority = IntegerField()

        postgres_db.register(Task)

        # Create tasks with known distribution
        high_priority_tasks = 0
        for i in range(50):
            priority = 1 if i < 10 else (2 if i < 30 else 3)
            if priority == 1:
                high_priority_tasks += 1
            Task.create(title=f"Task {i}", completed=False, priority=priority)

        # Delete all high priority tasks (priority = 1)
        deleted = Task.filter(priority=1).delete()
        assert deleted == high_priority_tasks

        # Verify count
        remaining = Task.filter().count()
        assert remaining == 50 - high_priority_tasks

    def test_postgres_delete_empty_result(self, postgres_db):
        """Test delete with no matching records returns 0."""

        class Category(Model):
            name = CharField(max_length=100)
            active = BooleanField(default=True)

        postgres_db.register(Category)

        Category.bulk_create(
            [
                Category(name="Electronics", active=True),
                Category(name="Books", active=True),
                Category(name="Clothing", active=True),
            ]
        )

        # Try to delete non-existent categories
        deleted = Category.filter(active=False).delete()
        assert deleted == 0

        # All categories should still exist
        remaining = Category.filter().count()
        assert remaining == 3

    def test_postgres_delete_all_records(self, postgres_db):
        """Test delete all records from table on PostgreSQL."""

        class TempData(Model):
            value = CharField(max_length=100)
            timestamp = IntegerField()

        postgres_db.register(TempData)

        # Create temporary data
        temp_items = []
        for i in range(25):
            temp_items.append(TempData(value=f"temp_{i}", timestamp=i))
        TempData.bulk_create(temp_items)

        # Delete all records
        deleted = TempData.filter().delete()
        assert deleted == 25

        # Verify table is empty
        assert TempData.filter().count() == 0

    def test_postgres_delete_with_complex_filter(self, postgres_db):
        """Test delete with complex filter combinations on PostgreSQL."""

        class Customer(Model):
            name = CharField(max_length=100)
            age = IntegerField()
            city = CharField(max_length=50)
            active = BooleanField(default=True)

        postgres_db.register(Customer)

        Customer.bulk_create(
            [
                Customer(name="Alice", age=25, city="New York", active=True),
                Customer(name="Bob", age=35, city="San Francisco", active=False),
                Customer(name="Charlie", age=45, city="New York", active=True),
                Customer(name="David", age=30, city="Chicago", active=True),
                Customer(name="Eve", age=28, city="New York", active=False),
            ]
        )

        # Delete inactive customers from New York
        deleted = Customer.filter(city="New York", active=False).delete()
        assert deleted == 1

        # Verify remaining customers
        remaining = Customer.filter().all()
        assert len(remaining) == 4

        # Verify Eve was deleted
        ny_customers = [c for c in remaining if c.city == "New York"]
        assert len(ny_customers) == 2
        assert all(c.active for c in ny_customers)
