# tests/unit/models/schema/test_order.py
"""Unit tests for order Pydantic schemas."""
import pytest
from pydantic import ValidationError

from models.schema.order import (
    OrderItemCreate,
    OrderItemResponse,
    OrderAddressCreate,
    OrderAddressResponse,
    OrderCreate,
    OrderUpdate,
    OrderResponse,
    OrderDetailResponse,
    OrderListResponse,
)


@pytest.mark.unit
@pytest.mark.schema
class TestOrderItemCreateSchema:
    """Test OrderItemCreate schema validation."""

    def test_valid_order_item(self):
        """Test valid order item creation."""
        item = OrderItemCreate(
            product_id=1,
            quantity=2,
        )
        assert item.product_id == 1
        assert item.quantity == 2

    def test_product_id_required(self):
        """Test product_id is required."""
        with pytest.raises(ValidationError) as exc_info:
            OrderItemCreate(quantity=2)
        assert "product_id" in str(exc_info.value).lower()

    def test_quantity_required(self):
        """Test quantity is required."""
        with pytest.raises(ValidationError) as exc_info:
            OrderItemCreate(product_id=1)
        assert "quantity" in str(exc_info.value).lower()

    def test_quantity_must_be_at_least_1(self):
        """Test quantity must be >= 1."""
        with pytest.raises(ValidationError) as exc_info:
            OrderItemCreate(
                product_id=1,
                quantity=0,
            )
        assert "quantity" in str(exc_info.value).lower()

    def test_negative_quantity_invalid(self):
        """Test negative quantity is invalid."""
        with pytest.raises(ValidationError):
            OrderItemCreate(
                product_id=1,
                quantity=-1,
            )


@pytest.mark.unit
@pytest.mark.schema
class TestOrderAddressCreateSchema:
    """Test OrderAddressCreate schema validation."""

    def test_valid_address(self):
        """Test valid order address creation."""
        address = OrderAddressCreate(
            first_name="John",
            last_name="Doe",
            address_line_1="123 Main St",
            city="Luxembourg",
            postal_code="L-1234",
            country="Luxembourg",
        )
        assert address.first_name == "John"
        assert address.city == "Luxembourg"

    def test_required_fields(self):
        """Test required fields validation."""
        with pytest.raises(ValidationError):
            OrderAddressCreate(
                first_name="John",
                # missing required fields
            )

    def test_optional_company(self):
        """Test optional company field."""
        address = OrderAddressCreate(
            first_name="John",
            last_name="Doe",
            company="Tech Corp",
            address_line_1="123 Main St",
            city="Luxembourg",
            postal_code="L-1234",
            country="Luxembourg",
        )
        assert address.company == "Tech Corp"

    def test_optional_address_line_2(self):
        """Test optional address_line_2 field."""
        address = OrderAddressCreate(
            first_name="John",
            last_name="Doe",
            address_line_1="123 Main St",
            address_line_2="Suite 500",
            city="Luxembourg",
            postal_code="L-1234",
            country="Luxembourg",
        )
        assert address.address_line_2 == "Suite 500"

    def test_first_name_min_length(self):
        """Test first_name minimum length."""
        with pytest.raises(ValidationError):
            OrderAddressCreate(
                first_name="",
                last_name="Doe",
                address_line_1="123 Main St",
                city="Luxembourg",
                postal_code="L-1234",
                country="Luxembourg",
            )

    def test_country_min_length(self):
        """Test country minimum length (2)."""
        with pytest.raises(ValidationError):
            OrderAddressCreate(
                first_name="John",
                last_name="Doe",
                address_line_1="123 Main St",
                city="Luxembourg",
                postal_code="L-1234",
                country="L",
            )


@pytest.mark.unit
@pytest.mark.schema
class TestOrderCreateSchema:
    """Test OrderCreate schema validation."""

    def test_valid_order(self):
        """Test valid order creation."""
        order = OrderCreate(
            items=[
                OrderItemCreate(product_id=1, quantity=2),
                OrderItemCreate(product_id=2, quantity=1),
            ],
            shipping_address=OrderAddressCreate(
                first_name="John",
                last_name="Doe",
                address_line_1="123 Main St",
                city="Luxembourg",
                postal_code="L-1234",
                country="Luxembourg",
            ),
        )
        assert len(order.items) == 2
        assert order.customer_id is None  # Optional for guest checkout

    def test_items_required(self):
        """Test items are required."""
        with pytest.raises(ValidationError) as exc_info:
            OrderCreate(
                shipping_address=OrderAddressCreate(
                    first_name="John",
                    last_name="Doe",
                    address_line_1="123 Main St",
                    city="Luxembourg",
                    postal_code="L-1234",
                    country="Luxembourg",
                ),
            )
        assert "items" in str(exc_info.value).lower()

    def test_items_must_not_be_empty(self):
        """Test items list must have at least 1 item."""
        with pytest.raises(ValidationError) as exc_info:
            OrderCreate(
                items=[],
                shipping_address=OrderAddressCreate(
                    first_name="John",
                    last_name="Doe",
                    address_line_1="123 Main St",
                    city="Luxembourg",
                    postal_code="L-1234",
                    country="Luxembourg",
                ),
            )
        assert "items" in str(exc_info.value).lower()

    def test_shipping_address_required(self):
        """Test shipping_address is required."""
        with pytest.raises(ValidationError) as exc_info:
            OrderCreate(
                items=[OrderItemCreate(product_id=1, quantity=1)],
            )
        assert "shipping_address" in str(exc_info.value).lower()

    def test_optional_billing_address(self):
        """Test billing_address is optional."""
        order = OrderCreate(
            items=[OrderItemCreate(product_id=1, quantity=1)],
            shipping_address=OrderAddressCreate(
                first_name="John",
                last_name="Doe",
                address_line_1="123 Main St",
                city="Luxembourg",
                postal_code="L-1234",
                country="Luxembourg",
            ),
            billing_address=OrderAddressCreate(
                first_name="Jane",
                last_name="Doe",
                address_line_1="456 Other St",
                city="Esch",
                postal_code="L-4321",
                country="Luxembourg",
            ),
        )
        assert order.billing_address is not None
        assert order.billing_address.first_name == "Jane"

    def test_optional_customer_notes(self):
        """Test optional customer_notes."""
        order = OrderCreate(
            items=[OrderItemCreate(product_id=1, quantity=1)],
            shipping_address=OrderAddressCreate(
                first_name="John",
                last_name="Doe",
                address_line_1="123 Main St",
                city="Luxembourg",
                postal_code="L-1234",
                country="Luxembourg",
            ),
            customer_notes="Please leave at door",
        )
        assert order.customer_notes == "Please leave at door"


@pytest.mark.unit
@pytest.mark.schema
class TestOrderUpdateSchema:
    """Test OrderUpdate schema validation."""

    def test_status_update(self):
        """Test valid status update."""
        update = OrderUpdate(status="processing")
        assert update.status == "processing"

    def test_valid_status_values(self):
        """Test all valid status values."""
        valid_statuses = ["pending", "processing", "shipped", "delivered", "cancelled", "refunded"]
        for status in valid_statuses:
            update = OrderUpdate(status=status)
            assert update.status == status

    def test_invalid_status(self):
        """Test invalid status raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            OrderUpdate(status="invalid_status")
        assert "status" in str(exc_info.value).lower()

    def test_tracking_number_update(self):
        """Test tracking number update."""
        update = OrderUpdate(tracking_number="TRACK123456")
        assert update.tracking_number == "TRACK123456"

    def test_internal_notes_update(self):
        """Test internal notes update."""
        update = OrderUpdate(internal_notes="Customer requested expedited shipping")
        assert update.internal_notes == "Customer requested expedited shipping"

    def test_empty_update_is_valid(self):
        """Test empty update is valid."""
        update = OrderUpdate()
        assert update.model_dump(exclude_unset=True) == {}


@pytest.mark.unit
@pytest.mark.schema
class TestOrderResponseSchema:
    """Test OrderResponse schema."""

    def test_from_dict(self):
        """Test creating response from dict."""
        from datetime import datetime

        data = {
            "id": 1,
            "vendor_id": 1,
            "customer_id": 1,
            "order_number": "ORD-001",
            "status": "pending",
            "subtotal": 100.00,
            "tax_amount": 20.00,
            "shipping_amount": 10.00,
            "discount_amount": 5.00,
            "total_amount": 125.00,
            "currency": "EUR",
            "shipping_method": "standard",
            "tracking_number": None,
            "customer_notes": None,
            "internal_notes": None,
            "created_at": datetime.now(),
            "updated_at": datetime.now(),
            "paid_at": None,
            "shipped_at": None,
            "delivered_at": None,
            "cancelled_at": None,
        }
        response = OrderResponse(**data)
        assert response.id == 1
        assert response.order_number == "ORD-001"
        assert response.total_amount == 125.00


@pytest.mark.unit
@pytest.mark.schema
class TestOrderItemResponseSchema:
    """Test OrderItemResponse schema."""

    def test_from_dict(self):
        """Test creating response from dict."""
        from datetime import datetime

        data = {
            "id": 1,
            "order_id": 1,
            "product_id": 1,
            "product_name": "Test Product",
            "product_sku": "SKU-001",
            "quantity": 2,
            "unit_price": 50.00,
            "total_price": 100.00,
            "inventory_reserved": True,
            "inventory_fulfilled": False,
            "created_at": datetime.now(),
            "updated_at": datetime.now(),
        }
        response = OrderItemResponse(**data)
        assert response.id == 1
        assert response.quantity == 2
        assert response.total_price == 100.00


@pytest.mark.unit
@pytest.mark.schema
class TestOrderListResponseSchema:
    """Test OrderListResponse schema."""

    def test_valid_list_response(self):
        """Test valid list response structure."""
        response = OrderListResponse(
            orders=[],
            total=0,
            skip=0,
            limit=10,
        )
        assert response.orders == []
        assert response.total == 0
        assert response.skip == 0
        assert response.limit == 10
