# tests/unit/models/schema/test_inventory.py
"""Unit tests for inventory Pydantic schemas."""

import pytest
from pydantic import ValidationError

from app.modules.inventory.schemas import (
    InventoryAdjust,
    InventoryCreate,
    InventoryLocationResponse,
    InventoryReserve,
    InventoryResponse,
    InventoryUpdate,
    ProductInventorySummary,
)


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryCreateSchema:
    """Test InventoryCreate schema validation."""

    def test_valid_inventory_create(self):
        """Test valid inventory creation data."""
        inventory = InventoryCreate(
            product_id=1,
            location="Warehouse A",
            quantity=100,
        )
        assert inventory.product_id == 1
        assert inventory.location == "Warehouse A"
        assert inventory.quantity == 100

    def test_product_id_required(self):
        """Test product_id is required."""
        with pytest.raises(ValidationError) as exc_info:
            InventoryCreate(location="Warehouse A", quantity=10)
        assert "product_id" in str(exc_info.value).lower()

    def test_location_required(self):
        """Test location is required."""
        with pytest.raises(ValidationError) as exc_info:
            InventoryCreate(product_id=1, quantity=10)
        assert "location" in str(exc_info.value).lower()

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

    def test_quantity_must_be_non_negative(self):
        """Test quantity must be >= 0."""
        with pytest.raises(ValidationError) as exc_info:
            InventoryCreate(
                product_id=1,
                location="Warehouse A",
                quantity=-5,
            )
        assert "quantity" in str(exc_info.value).lower()

    def test_quantity_zero_is_valid(self):
        """Test quantity of 0 is valid."""
        inventory = InventoryCreate(
            product_id=1,
            location="Warehouse A",
            quantity=0,
        )
        assert inventory.quantity == 0


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryAdjustSchema:
    """Test InventoryAdjust schema validation."""

    def test_positive_adjustment(self):
        """Test positive quantity adjustment (add stock)."""
        adjustment = InventoryAdjust(
            product_id=1,
            location="Warehouse A",
            quantity=50,
        )
        assert adjustment.quantity == 50

    def test_negative_adjustment(self):
        """Test negative quantity adjustment (remove stock)."""
        adjustment = InventoryAdjust(
            product_id=1,
            location="Warehouse A",
            quantity=-20,
        )
        assert adjustment.quantity == -20

    def test_zero_adjustment_is_valid(self):
        """Test zero adjustment is technically valid."""
        adjustment = InventoryAdjust(
            product_id=1,
            location="Warehouse A",
            quantity=0,
        )
        assert adjustment.quantity == 0


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryUpdateSchema:
    """Test InventoryUpdate schema validation."""

    def test_partial_update(self):
        """Test partial update with only some fields."""
        update = InventoryUpdate(quantity=150)
        assert update.quantity == 150
        assert update.reserved_quantity is None
        assert update.location is None

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

    def test_quantity_must_be_non_negative(self):
        """Test quantity must be >= 0 in update."""
        with pytest.raises(ValidationError):
            InventoryUpdate(quantity=-10)

    def test_reserved_quantity_must_be_non_negative(self):
        """Test reserved_quantity must be >= 0."""
        with pytest.raises(ValidationError):
            InventoryUpdate(reserved_quantity=-5)

    def test_location_update(self):
        """Test location can be updated."""
        update = InventoryUpdate(location="Warehouse B")
        assert update.location == "Warehouse B"


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryReserveSchema:
    """Test InventoryReserve schema validation."""

    def test_valid_reservation(self):
        """Test valid inventory reservation."""
        reservation = InventoryReserve(
            product_id=1,
            location="Warehouse A",
            quantity=10,
        )
        assert reservation.product_id == 1
        assert reservation.quantity == 10

    def test_quantity_must_be_positive(self):
        """Test reservation quantity must be > 0."""
        with pytest.raises(ValidationError) as exc_info:
            InventoryReserve(
                product_id=1,
                location="Warehouse A",
                quantity=0,
            )
        assert "quantity" in str(exc_info.value).lower()

    def test_negative_quantity_invalid(self):
        """Test negative reservation quantity is invalid."""
        with pytest.raises(ValidationError):
            InventoryReserve(
                product_id=1,
                location="Warehouse A",
                quantity=-5,
            )


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryResponseSchema:
    """Test InventoryResponse schema."""

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

        data = {
            "id": 1,
            "product_id": 1,
            "store_id": 1,
            "bin_location": "Warehouse A",
            "quantity": 100,
            "reserved_quantity": 20,
            "gtin": "1234567890123",
            "created_at": datetime.now(),
            "updated_at": datetime.now(),
        }
        response = InventoryResponse(**data)
        assert response.id == 1
        assert response.quantity == 100
        assert response.reserved_quantity == 20

    def test_available_quantity_property(self):
        """Test available_quantity calculated property."""
        from datetime import datetime

        data = {
            "id": 1,
            "product_id": 1,
            "store_id": 1,
            "bin_location": "Warehouse A",
            "quantity": 100,
            "reserved_quantity": 30,
            "gtin": None,
            "created_at": datetime.now(),
            "updated_at": datetime.now(),
        }
        response = InventoryResponse(**data)
        assert response.available_quantity == 70

    def test_available_quantity_never_negative(self):
        """Test available_quantity is never negative."""
        from datetime import datetime

        data = {
            "id": 1,
            "product_id": 1,
            "store_id": 1,
            "bin_location": "Warehouse A",
            "quantity": 10,
            "reserved_quantity": 50,  # Over-reserved
            "gtin": None,
            "created_at": datetime.now(),
            "updated_at": datetime.now(),
        }
        response = InventoryResponse(**data)
        assert response.available_quantity == 0


@pytest.mark.unit
@pytest.mark.schema
class TestInventoryLocationResponseSchema:
    """Test InventoryLocationResponse schema."""

    def test_valid_location_response(self):
        """Test valid location response."""
        location = InventoryLocationResponse(
            location="Warehouse A",
            quantity=100,
            reserved_quantity=20,
            available_quantity=80,
        )
        assert location.location == "Warehouse A"
        assert location.quantity == 100
        assert location.available_quantity == 80


@pytest.mark.unit
@pytest.mark.schema
class TestProductInventorySummarySchema:
    """Test ProductInventorySummary schema."""

    def test_valid_summary(self):
        """Test valid inventory summary."""
        summary = ProductInventorySummary(
            product_id=1,
            store_id=1,
            product_sku="SKU-001",
            product_title="Test Product",
            total_quantity=200,
            total_reserved=50,
            total_available=150,
            locations=[
                InventoryLocationResponse(
                    location="Warehouse A",
                    quantity=100,
                    reserved_quantity=25,
                    available_quantity=75,
                ),
                InventoryLocationResponse(
                    location="Warehouse B",
                    quantity=100,
                    reserved_quantity=25,
                    available_quantity=75,
                ),
            ],
        )
        assert summary.product_id == 1
        assert summary.total_quantity == 200
        assert len(summary.locations) == 2

    def test_empty_locations(self):
        """Test summary with no locations."""
        summary = ProductInventorySummary(
            product_id=1,
            store_id=1,
            product_sku=None,
            product_title="Test Product",
            total_quantity=0,
            total_reserved=0,
            total_available=0,
            locations=[],
        )
        assert summary.locations == []
