# tests/unit/models/database/test_order.py
"""Unit tests for Order and OrderItem database models."""

from datetime import UTC, datetime

import pytest
from sqlalchemy.exc import IntegrityError

from app.modules.orders.models import Order, OrderItem


def create_order_with_snapshots(
    db,
    store,
    customer,
    customer_address,
    order_number,
    status="pending",
    subtotal=99.99,
    total_amount=99.99,
    **kwargs
):
    """Helper to create Order with required address snapshots."""
    # Remove channel from kwargs if present (we set it explicitly)
    channel = kwargs.pop("channel", "direct")

    order = Order(
        store_id=store.id,
        customer_id=customer.id,
        order_number=order_number,
        status=status,
        channel=channel,
        subtotal=subtotal,
        total_amount=total_amount,
        currency="EUR",
        order_date=datetime.now(UTC),
        # Customer snapshot
        customer_first_name=customer.first_name,
        customer_last_name=customer.last_name,
        customer_email=customer.email,
        # Shipping address snapshot
        ship_first_name=customer_address.first_name,
        ship_last_name=customer_address.last_name,
        ship_address_line_1=customer_address.address_line_1,
        ship_city=customer_address.city,
        ship_postal_code=customer_address.postal_code,
        ship_country_iso="LU",
        # Billing address snapshot
        bill_first_name=customer_address.first_name,
        bill_last_name=customer_address.last_name,
        bill_address_line_1=customer_address.address_line_1,
        bill_city=customer_address.city,
        bill_postal_code=customer_address.postal_code,
        bill_country_iso="LU",
        **kwargs
    )
    db.add(order)
    db.commit()
    db.refresh(order)
    return order


@pytest.mark.unit
@pytest.mark.database
class TestOrderModel:
    """Test Order model."""

    def test_order_creation(
        self, db, test_store, test_customer, test_customer_address
    ):
        """Test Order model with customer relationship."""
        order = create_order_with_snapshots(
            db, test_store, test_customer, test_customer_address,
            order_number="ORD-001",
        )

        assert order.id is not None
        assert order.store_id == test_store.id
        assert order.customer_id == test_customer.id
        assert order.order_number == "ORD-001"
        assert order.status == "pending"
        assert float(order.total_amount) == 99.99
        # Verify snapshots
        assert order.customer_first_name == test_customer.first_name
        assert order.ship_city == test_customer_address.city
        assert order.ship_country_iso == "LU"

    def test_order_number_uniqueness(
        self, db, test_store, test_customer, test_customer_address
    ):
        """Test order_number unique constraint."""
        create_order_with_snapshots(
            db, test_store, test_customer, test_customer_address,
            order_number="UNIQUE-ORD-001",
        )

        # Duplicate order number should fail
        with pytest.raises(IntegrityError):
            create_order_with_snapshots(
                db, test_store, test_customer, test_customer_address,
                order_number="UNIQUE-ORD-001",
            )

    def test_order_status_values(
        self, db, test_store, test_customer, test_customer_address
    ):
        """Test Order with different status values."""
        statuses = [
            "pending",
            "processing",
            "shipped",
            "delivered",
            "cancelled",
            "refunded",
        ]

        for i, status in enumerate(statuses):
            order = create_order_with_snapshots(
                db, test_store, test_customer, test_customer_address,
                order_number=f"STATUS-ORD-{i:03d}",
                status=status,
            )
            assert order.status == status

    def test_order_amounts(self, db, test_store, test_customer, test_customer_address):
        """Test Order amount fields."""
        order = create_order_with_snapshots(
            db, test_store, test_customer, test_customer_address,
            order_number="AMOUNTS-ORD-001",
            subtotal=100.00,
            tax_amount=20.00,
            shipping_amount=10.00,
            discount_amount=5.00,
            total_amount=125.00,
        )

        assert float(order.subtotal) == 100.00
        assert float(order.tax_amount) == 20.00
        assert float(order.shipping_amount) == 10.00
        assert float(order.discount_amount) == 5.00
        assert float(order.total_amount) == 125.00

    def test_order_relationships(
        self, db, test_store, test_customer, test_customer_address
    ):
        """Test Order relationships."""
        order = create_order_with_snapshots(
            db, test_store, test_customer, test_customer_address,
            order_number="REL-ORD-001",
        )

        assert order.store is not None
        assert order.customer is not None
        assert order.store.id == test_store.id
        assert order.customer.id == test_customer.id


@pytest.mark.unit
@pytest.mark.database
class TestOrderItemModel:
    """Test OrderItem model."""

    def test_order_item_creation(self, db, test_order, test_product):
        """Test OrderItem model."""
        # Get title from translation
        product_title = test_product.marketplace_product.get_title("en")

        order_item = OrderItem(
            order_id=test_order.id,
            product_id=test_product.id,
            product_name=product_title,
            product_sku=test_product.store_sku or "SKU001",
            quantity=2,
            unit_price=49.99,
            total_price=99.98,
        )

        db.add(order_item)
        db.commit()
        db.refresh(order_item)

        assert order_item.id is not None
        assert order_item.order_id == test_order.id
        assert order_item.product_id == test_product.id
        assert order_item.quantity == 2
        assert float(order_item.unit_price) == 49.99
        assert float(order_item.total_price) == 99.98

    def test_order_item_stores_product_snapshot(self, db, test_order, test_product):
        """Test OrderItem stores product name and SKU as snapshot."""
        order_item = OrderItem(
            order_id=test_order.id,
            product_id=test_product.id,
            product_name="Snapshot Product Name",
            product_sku="SNAPSHOT-SKU-001",
            quantity=1,
            unit_price=25.00,
            total_price=25.00,
        )

        db.add(order_item)
        db.commit()
        db.refresh(order_item)

        assert order_item.id is not None
        assert order_item.product_name == "Snapshot Product Name"
        assert order_item.product_sku == "SNAPSHOT-SKU-001"

    def test_order_item_relationships(self, db, test_order, test_product):
        """Test OrderItem relationships."""
        order_item = OrderItem(
            order_id=test_order.id,
            product_id=test_product.id,
            product_name="Test Product",
            product_sku="SKU001",
            quantity=1,
            unit_price=50.00,
            total_price=50.00,
        )

        db.add(order_item)
        db.commit()
        db.refresh(order_item)

        assert order_item.order is not None
        assert order_item.order.id == test_order.id

    def test_multiple_items_per_order(self, db, test_order, test_product):
        """Test multiple OrderItems can belong to same Order."""
        # Create two order items for the same product (different quantities)
        item1 = OrderItem(
            order_id=test_order.id,
            product_id=test_product.id,
            product_name="Product - Size M",
            product_sku="SKU001-M",
            quantity=1,
            unit_price=25.00,
            total_price=25.00,
        )
        item2 = OrderItem(
            order_id=test_order.id,
            product_id=test_product.id,
            product_name="Product - Size L",
            product_sku="SKU001-L",
            quantity=2,
            unit_price=30.00,
            total_price=60.00,
        )

        db.add_all([item1, item2])
        db.commit()

        assert item1.order_id == item2.order_id
        assert item1.id != item2.id
        assert item1.product_id == item2.product_id  # Same product, different items
