# tests/unit/services/test_inventory_service.py
"""Unit tests for InventoryService."""

import uuid

import pytest

from app.modules.catalog.exceptions import ProductNotFoundException
from app.modules.inventory.exceptions import (
    InsufficientInventoryException,
    InvalidQuantityException,
    InventoryNotFoundException,
    InventoryValidationException,
)
from app.modules.inventory.models import Inventory
from app.modules.inventory.schemas import (
    InventoryAdjust,
    InventoryCreate,
    InventoryReserve,
    InventoryUpdate,
)
from app.modules.inventory.services.inventory_service import InventoryService


@pytest.mark.unit
@pytest.mark.inventory
class TestInventoryService:
    """Test suite for InventoryService."""

    def setup_method(self):
        """Initialize service instance before each test."""
        self.service = InventoryService()

    # ==================== Validation Helper Tests ====================

    def test_validate_quantity_positive(self):
        """Test that positive quantity passes validation."""
        # Should not raise
        self.service._validate_quantity(10, allow_zero=True)
        self.service._validate_quantity(10, allow_zero=False)

    def test_validate_quantity_zero_allowed(self):
        """Test that zero quantity passes when allow_zero=True."""
        # Should not raise
        self.service._validate_quantity(0, allow_zero=True)

    def test_validate_quantity_zero_not_allowed(self):
        """Test that zero quantity fails when allow_zero=False."""
        with pytest.raises(InvalidQuantityException) as exc_info:
            self.service._validate_quantity(0, allow_zero=False)

        assert exc_info.value.error_code == "INVALID_QUANTITY"
        assert "must be positive" in str(exc_info.value)

    def test_validate_quantity_negative(self):
        """Test that negative quantity fails validation."""
        with pytest.raises(InvalidQuantityException) as exc_info:
            self.service._validate_quantity(-5, allow_zero=True)

        assert exc_info.value.error_code == "INVALID_QUANTITY"
        assert "cannot be negative" in str(exc_info.value)

    def test_validate_quantity_none(self):
        """Test that None quantity fails validation."""
        with pytest.raises(InvalidQuantityException) as exc_info:
            self.service._validate_quantity(None, allow_zero=True)

        assert exc_info.value.error_code == "INVALID_QUANTITY"
        assert "required" in str(exc_info.value)

    def test_validate_location_valid(self):
        """Test valid location normalization."""
        result = self.service._validate_location("warehouse_a")
        assert result == "WAREHOUSE_A"

    def test_validate_location_with_whitespace(self):
        """Test location normalization strips whitespace."""
        result = self.service._validate_location("  warehouse_a  ")
        assert result == "WAREHOUSE_A"

    def test_validate_location_empty(self):
        """Test empty location fails validation."""
        with pytest.raises(InventoryValidationException) as exc_info:
            self.service._validate_location("")

        assert "required" in str(exc_info.value)

    def test_validate_location_whitespace_only(self):
        """Test whitespace-only location fails validation."""
        with pytest.raises(InventoryValidationException) as exc_info:
            self.service._validate_location("   ")

        assert "required" in str(exc_info.value)

    # ==================== Set Inventory Tests ====================

    def test_set_inventory_new_entry_success(self, db, test_product, test_store):
        """Test setting inventory for a new product/location combination."""
        unique_id = str(uuid.uuid4())[:8].upper()
        inventory_data = InventoryCreate(
            product_id=test_product.id,
            location=f"WAREHOUSE_NEW_{unique_id}",
            quantity=100,
        )

        result = self.service.set_inventory(db, test_store.id, inventory_data)

        assert result.product_id == test_product.id
        assert result.store_id == test_store.id
        assert result.bin_location == f"WAREHOUSE_NEW_{unique_id}"
        assert result.quantity == 100

    def test_set_inventory_existing_entry_replaces(
        self, db, test_inventory, test_product, test_store
    ):
        """Test setting inventory replaces existing quantity."""
        inventory_data = InventoryCreate(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=200,
        )

        result = self.service.set_inventory(db, test_store.id, inventory_data)

        assert result.quantity == 200  # Replaced, not added

    def test_set_inventory_product_not_found(self, db, test_store):
        """Test setting inventory for non-existent product raises exception."""
        from app.exceptions import ValidationException

        unique_id = str(uuid.uuid4())[:8].upper()
        inventory_data = InventoryCreate(
            product_id=99999,  # Non-existent product
            location=f"WAREHOUSE_{unique_id}",
            quantity=100,
        )

        # Service wraps ProductNotFoundException in ValidationException
        with pytest.raises((ProductNotFoundException, ValidationException)):
            self.service.set_inventory(db, test_store.id, inventory_data)

    def test_set_inventory_zero_quantity(self, db, test_product, test_store):
        """Test setting inventory with zero quantity succeeds."""
        unique_id = str(uuid.uuid4())[:8].upper()
        inventory_data = InventoryCreate(
            product_id=test_product.id,
            location=f"WAREHOUSE_ZERO_{unique_id}",
            quantity=0,
        )

        result = self.service.set_inventory(db, test_store.id, inventory_data)

        assert result.quantity == 0

    # ==================== Adjust Inventory Tests ====================

    def test_adjust_inventory_add_new_entry(self, db, test_product, test_store):
        """Test adjusting inventory creates new entry with positive quantity."""
        unique_id = str(uuid.uuid4())[:8].upper()
        inventory_data = InventoryAdjust(
            product_id=test_product.id,
            location=f"WAREHOUSE_ADJUST_{unique_id}",
            quantity=50,
        )

        result = self.service.adjust_inventory(db, test_store.id, inventory_data)

        assert result.quantity == 50

    def test_adjust_inventory_add_to_existing(
        self, db, test_inventory, test_product, test_store
    ):
        """Test adjusting inventory adds to existing quantity."""
        original_quantity = test_inventory.quantity

        inventory_data = InventoryAdjust(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=25,
        )

        result = self.service.adjust_inventory(db, test_store.id, inventory_data)

        assert result.quantity == original_quantity + 25

    def test_adjust_inventory_remove_from_existing(
        self, db, test_inventory, test_product, test_store
    ):
        """Test adjusting inventory removes from existing quantity."""
        original_quantity = test_inventory.quantity

        inventory_data = InventoryAdjust(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=-10,
        )

        result = self.service.adjust_inventory(db, test_store.id, inventory_data)

        assert result.quantity == original_quantity - 10

    def test_adjust_inventory_remove_insufficient(
        self, db, test_inventory, test_product, test_store
    ):
        """Test removing more than available raises exception."""
        from app.exceptions import ValidationException

        inventory_data = InventoryAdjust(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=-(test_inventory.quantity + 100),  # More than available
        )

        # Service wraps InsufficientInventoryException in ValidationException
        with pytest.raises((InsufficientInventoryException, ValidationException)):
            self.service.adjust_inventory(db, test_store.id, inventory_data)

    def test_adjust_inventory_remove_nonexistent(self, db, test_product, test_store):
        """Test removing from non-existent inventory raises InventoryNotFoundException."""
        unique_id = str(uuid.uuid4())[:8].upper()
        inventory_data = InventoryAdjust(
            product_id=test_product.id,
            location=f"NONEXISTENT_{unique_id}",
            quantity=-10,
        )

        with pytest.raises(InventoryNotFoundException):
            self.service.adjust_inventory(db, test_store.id, inventory_data)

    # ==================== Reserve Inventory Tests ====================

    def test_reserve_inventory_success(
        self, db, test_inventory, test_product, test_store
    ):
        """Test reserving inventory succeeds."""
        original_reserved = test_inventory.reserved_quantity
        available = test_inventory.quantity - test_inventory.reserved_quantity
        reserve_qty = min(10, available)

        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=reserve_qty,
        )

        result = self.service.reserve_inventory(db, test_store.id, reserve_data)

        assert result.reserved_quantity == original_reserved + reserve_qty

    def test_reserve_inventory_insufficient_available(
        self, db, test_inventory, test_product, test_store
    ):
        """Test reserving more than available raises exception."""
        from app.exceptions import ValidationException

        available = test_inventory.quantity - test_inventory.reserved_quantity

        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=available + 100,  # More than available
        )

        # Service wraps InsufficientInventoryException in ValidationException
        with pytest.raises((InsufficientInventoryException, ValidationException)):
            self.service.reserve_inventory(db, test_store.id, reserve_data)

    def test_reserve_inventory_not_found(self, db, test_product, test_store):
        """Test reserving non-existent inventory raises InventoryNotFoundException."""
        unique_id = str(uuid.uuid4())[:8].upper()
        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=f"NONEXISTENT_{unique_id}",
            quantity=10,
        )

        with pytest.raises(InventoryNotFoundException):
            self.service.reserve_inventory(db, test_store.id, reserve_data)

    # ==================== Release Reservation Tests ====================

    def test_release_reservation_success(
        self, db, test_inventory, test_product, test_store
    ):
        """Test releasing reservation succeeds."""
        original_reserved = test_inventory.reserved_quantity
        release_qty = min(5, original_reserved)

        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=release_qty,
        )

        result = self.service.release_reservation(db, test_store.id, reserve_data)

        assert result.reserved_quantity == original_reserved - release_qty

    def test_release_reservation_more_than_reserved(
        self, db, test_inventory, test_product, test_store
    ):
        """Test releasing more than reserved sets to zero (doesn't error)."""
        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=test_inventory.reserved_quantity + 100,
        )

        result = self.service.release_reservation(db, test_store.id, reserve_data)

        assert result.reserved_quantity == 0

    # ==================== Fulfill Reservation Tests ====================

    def test_fulfill_reservation_success(
        self, db, test_inventory, test_product, test_store
    ):
        """Test fulfilling reservation decreases both quantity and reserved."""
        original_quantity = test_inventory.quantity
        original_reserved = test_inventory.reserved_quantity
        fulfill_qty = min(5, original_reserved, original_quantity)

        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=fulfill_qty,
        )

        result = self.service.fulfill_reservation(db, test_store.id, reserve_data)

        assert result.quantity == original_quantity - fulfill_qty
        assert result.reserved_quantity == max(0, original_reserved - fulfill_qty)

    def test_fulfill_reservation_insufficient_inventory(
        self, db, test_inventory, test_product, test_store
    ):
        """Test fulfilling more than quantity raises exception."""
        from app.exceptions import ValidationException

        reserve_data = InventoryReserve(
            product_id=test_product.id,
            location=test_inventory.bin_location,
            quantity=test_inventory.quantity + 100,
        )

        # Service wraps InsufficientInventoryException in ValidationException
        with pytest.raises((InsufficientInventoryException, ValidationException)):
            self.service.fulfill_reservation(db, test_store.id, reserve_data)

    # ==================== Get Product Inventory Tests ====================

    def test_get_product_inventory_success(
        self, db, test_inventory, test_product, test_store
    ):
        """Test getting product inventory summary."""
        result = self.service.get_product_inventory(db, test_store.id, test_product.id)

        assert result.product_id == test_product.id
        assert result.store_id == test_store.id
        assert result.total_quantity >= test_inventory.quantity
        assert len(result.locations) >= 1

    def test_get_product_inventory_no_inventory(self, db, test_product, test_store):
        """Test getting inventory for product with no inventory entries."""
        # Create a new product without inventory
        from app.modules.catalog.models import Product
        from app.modules.marketplace.models import (
            MarketplaceProduct,
            MarketplaceProductTranslation,
        )

        unique_id = str(uuid.uuid4())[:8]
        mp = MarketplaceProduct(
            marketplace_product_id=f"MP_EMPTY_{unique_id}",
            price="29.99",
            marketplace="Letzshop",
        )
        db.add(mp)
        db.flush()

        # Create translation for the product (title is now in translations table)
        translation = MarketplaceProductTranslation(
            marketplace_product_id=mp.id,
            language="en",
            title="Product Without Inventory",
        )
        db.add(translation)
        db.commit()

        product = Product(
            store_id=test_store.id,
            marketplace_product_id=mp.id,
            is_active=True,
        )
        db.add(product)
        db.commit()

        result = self.service.get_product_inventory(db, test_store.id, product.id)

        assert result.total_quantity == 0
        assert result.total_reserved == 0
        assert len(result.locations) == 0

    def test_get_product_inventory_not_found(self, db, test_store):
        """Test getting inventory for non-existent product raises exception."""
        from app.exceptions import ValidationException

        # Service wraps ProductNotFoundException in ValidationException
        with pytest.raises((ProductNotFoundException, ValidationException)):
            self.service.get_product_inventory(db, test_store.id, 99999)

    # ==================== Get Store Inventory Tests ====================

    def test_get_store_inventory_success(self, db, test_inventory, test_store):
        """Test getting all store inventory."""
        result = self.service.get_store_inventory(db, test_store.id)

        assert len(result) >= 1
        assert any(inv.id == test_inventory.id for inv in result)

    def test_get_store_inventory_with_location_filter(
        self, db, test_inventory, test_store
    ):
        """Test getting store inventory filtered by location."""
        result = self.service.get_store_inventory(
            db, test_store.id, location=test_inventory.bin_location[:10]
        )

        assert len(result) >= 1
        for inv in result:
            assert test_inventory.bin_location[:10].upper() in inv.bin_location.upper()

    def test_get_store_inventory_with_low_stock_filter(self, db, test_store):
        """Test getting store inventory filtered by low stock threshold."""
        result = self.service.get_store_inventory(
            db, test_store.id, low_stock_threshold=5
        )

        for inv in result:
            assert inv.quantity <= 5

    def test_get_store_inventory_pagination(self, db, test_store):
        """Test store inventory pagination."""
        result = self.service.get_store_inventory(db, test_store.id, skip=0, limit=10)

        assert len(result) <= 10

    # ==================== Update Inventory Tests ====================

    def test_update_inventory_quantity(self, db, test_inventory, test_store):
        """Test updating inventory quantity."""
        inventory_update = InventoryUpdate(quantity=500)

        result = self.service.update_inventory(
            db, test_store.id, test_inventory.id, inventory_update
        )

        assert result.quantity == 500

    def test_update_inventory_reserved_quantity(self, db, test_inventory, test_store):
        """Test updating inventory reserved quantity."""
        inventory_update = InventoryUpdate(reserved_quantity=20)

        result = self.service.update_inventory(
            db, test_store.id, test_inventory.id, inventory_update
        )

        assert result.reserved_quantity == 20

    def test_update_inventory_location(self, db, test_inventory, test_store):
        """Test updating inventory location."""
        unique_id = str(uuid.uuid4())[:8].upper()
        new_location = f"NEW_LOCATION_{unique_id}"
        inventory_update = InventoryUpdate(location=new_location)

        result = self.service.update_inventory(
            db, test_store.id, test_inventory.id, inventory_update
        )

        assert result.bin_location == new_location.upper()

    def test_update_inventory_not_found(self, db, test_store):
        """Test updating non-existent inventory raises InventoryNotFoundException."""
        inventory_update = InventoryUpdate(quantity=100)

        with pytest.raises(InventoryNotFoundException):
            self.service.update_inventory(db, test_store.id, 99999, inventory_update)

    def test_update_inventory_wrong_store(self, db, test_inventory, other_merchant):
        """Test updating inventory from wrong store raises InventoryNotFoundException."""
        from app.modules.tenancy.models import Store

        unique_id = str(uuid.uuid4())[:8]
        other_store = Store(
            merchant_id=other_merchant.id,
            store_code=f"OTHER_{unique_id.upper()}",
            subdomain=f"other{unique_id.lower()}",
            name=f"Other Store {unique_id}",
            is_active=True,
        )
        db.add(other_store)
        db.commit()

        inventory_update = InventoryUpdate(quantity=100)

        with pytest.raises(InventoryNotFoundException):
            self.service.update_inventory(
                db, other_store.id, test_inventory.id, inventory_update
            )

    # ==================== Delete Inventory Tests ====================

    def test_delete_inventory_success(self, db, test_inventory, test_store):
        """Test deleting inventory entry."""
        inventory_id = test_inventory.id

        result = self.service.delete_inventory(db, test_store.id, inventory_id)

        assert result is True

        # Verify deleted
        deleted = db.query(Inventory).filter(Inventory.id == inventory_id).first()
        assert deleted is None

    def test_delete_inventory_not_found(self, db, test_store):
        """Test deleting non-existent inventory raises InventoryNotFoundException."""
        with pytest.raises(InventoryNotFoundException):
            self.service.delete_inventory(db, test_store.id, 99999)

    def test_delete_inventory_wrong_store(self, db, test_inventory, other_merchant):
        """Test deleting inventory from wrong store raises InventoryNotFoundException."""
        from app.modules.tenancy.models import Store

        unique_id = str(uuid.uuid4())[:8]
        other_store = Store(
            merchant_id=other_merchant.id,
            store_code=f"DELOTHER_{unique_id.upper()}",
            subdomain=f"delother{unique_id.lower()}",
            name=f"Delete Other Store {unique_id}",
            is_active=True,
        )
        db.add(other_store)
        db.commit()

        with pytest.raises(InventoryNotFoundException):
            self.service.delete_inventory(db, other_store.id, test_inventory.id)

    # ==================== Admin Method Tests ====================

    def test_get_all_inventory_admin_success(self, db, test_inventory):
        """Test get_all_inventory_admin returns all inventory."""
        result = self.service.get_all_inventory_admin(db)

        assert result.total >= 1
        assert len(result.inventories) >= 1
        assert any(inv.id == test_inventory.id for inv in result.inventories)

    def test_get_all_inventory_admin_with_store_filter(
        self, db, test_inventory, test_store
    ):
        """Test get_all_inventory_admin filters by store."""
        result = self.service.get_all_inventory_admin(
            db, store_id=test_store.id
        )

        for inv in result.inventories:
            assert inv.store_id == test_store.id

    def test_get_all_inventory_admin_with_location_filter(
        self, db, test_inventory
    ):
        """Test get_all_inventory_admin filters by location."""
        location_prefix = test_inventory.bin_location[:5]
        result = self.service.get_all_inventory_admin(
            db, location=location_prefix
        )

        for inv in result.inventories:
            assert location_prefix.upper() in inv.location.upper()

    def test_get_all_inventory_admin_with_low_stock_filter(self, db):
        """Test get_all_inventory_admin filters by low stock."""
        result = self.service.get_all_inventory_admin(db, low_stock=5)

        for inv in result.inventories:
            assert inv.quantity <= 5

    def test_get_all_inventory_admin_pagination(self, db):
        """Test get_all_inventory_admin pagination."""
        result = self.service.get_all_inventory_admin(db, skip=0, limit=5)

        assert len(result.inventories) <= 5
        assert result.skip == 0
        assert result.limit == 5

    def test_get_inventory_stats_admin(self, db, test_inventory):
        """Test get_inventory_stats_admin returns stats."""
        result = self.service.get_inventory_stats_admin(db)

        assert result.total_entries >= 1
        assert result.total_quantity >= test_inventory.quantity
        assert result.total_reserved >= 0
        assert result.total_available >= 0
        assert result.low_stock_count >= 0
        assert result.stores_with_inventory >= 1
        assert result.unique_locations >= 1

    def test_get_low_stock_items_admin(self, db, test_product, test_store):
        """Test get_low_stock_items_admin returns low stock items."""
        # Create low stock inventory
        unique_id = str(uuid.uuid4())[:8].upper()
        low_stock_inv = Inventory(
            product_id=test_product.id,
            store_id=test_store.id,
            warehouse="strassen",
            bin_location=f"LOW_{unique_id}",
            quantity=3,
            reserved_quantity=0,
        )
        db.add(low_stock_inv)
        db.commit()

        result = self.service.get_low_stock_items_admin(db, threshold=10)

        assert len(result) >= 1
        for item in result:
            assert item.quantity <= 10

    def test_get_low_stock_items_admin_with_store_filter(
        self, db, test_inventory, test_store
    ):
        """Test get_low_stock_items_admin filters by store."""
        result = self.service.get_low_stock_items_admin(
            db, threshold=1000, store_id=test_store.id
        )

        for item in result:
            assert item.store_id == test_store.id

    def test_get_stores_with_inventory_admin(self, db, test_inventory, test_store):
        """Test get_stores_with_inventory_admin returns stores list."""
        result = self.service.get_stores_with_inventory_admin(db)

        assert len(result.stores) >= 1
        assert any(v.id == test_store.id for v in result.stores)

    def test_get_inventory_locations_admin(self, db, test_inventory):
        """Test get_inventory_locations_admin returns locations."""
        result = self.service.get_inventory_locations_admin(db)

        assert len(result.locations) >= 1
        assert test_inventory.bin_location in result.locations

    def test_get_inventory_locations_admin_with_store_filter(
        self, db, test_inventory, test_store
    ):
        """Test get_inventory_locations_admin filters by store."""
        result = self.service.get_inventory_locations_admin(
            db, store_id=test_store.id
        )

        assert len(result.locations) >= 1

    def test_get_store_inventory_admin_success(
        self, db, test_inventory, test_store
    ):
        """Test get_store_inventory_admin returns store inventory."""
        result = self.service.get_store_inventory_admin(
            db, store_id=test_store.id
        )

        assert result.total >= 1
        assert result.store_filter == test_store.id
        for inv in result.inventories:
            assert inv.store_id == test_store.id

    def test_get_store_inventory_admin_store_not_found(self, db):
        """Test get_store_inventory_admin raises for non-existent store."""
        from app.modules.tenancy.exceptions import StoreNotFoundException

        with pytest.raises(StoreNotFoundException):
            self.service.get_store_inventory_admin(db, store_id=99999)

    def test_get_product_inventory_admin(self, db, test_inventory, test_product):
        """Test get_product_inventory_admin returns product inventory."""
        result = self.service.get_product_inventory_admin(db, test_product.id)

        assert result.product_id == test_product.id
        assert result.total_quantity >= test_inventory.quantity

    def test_get_product_inventory_admin_not_found(self, db):
        """Test get_product_inventory_admin raises for non-existent product."""
        with pytest.raises(ProductNotFoundException):
            self.service.get_product_inventory_admin(db, 99999)

    def test_verify_store_exists_success(self, db, test_store):
        """Test verify_store_exists returns store."""
        result = self.service.verify_store_exists(db, test_store.id)

        assert result.id == test_store.id

    def test_verify_store_exists_not_found(self, db):
        """Test verify_store_exists raises for non-existent store."""
        from app.modules.tenancy.exceptions import StoreNotFoundException

        with pytest.raises(StoreNotFoundException):
            self.service.verify_store_exists(db, 99999)

    def test_get_inventory_by_id_admin_success(self, db, test_inventory):
        """Test get_inventory_by_id_admin returns inventory."""
        result = self.service.get_inventory_by_id_admin(db, test_inventory.id)

        assert result.id == test_inventory.id

    def test_get_inventory_by_id_admin_not_found(self, db):
        """Test get_inventory_by_id_admin raises for non-existent."""
        with pytest.raises(InventoryNotFoundException):
            self.service.get_inventory_by_id_admin(db, 99999)

    # ==================== Private Helper Tests ====================

    def test_get_store_product_success(self, db, test_product, test_store):
        """Test _get_store_product returns product."""
        result = self.service._get_store_product(
            db, test_store.id, test_product.id
        )

        assert result.id == test_product.id

    def test_get_store_product_not_found(self, db, test_store):
        """Test _get_store_product raises for non-existent product."""
        with pytest.raises(ProductNotFoundException):
            self.service._get_store_product(db, test_store.id, 99999)

    def test_get_store_product_wrong_store(
        self, db, test_product, other_merchant
    ):
        """Test _get_store_product raises for wrong store."""
        from app.modules.tenancy.models import Store

        unique_id = str(uuid.uuid4())[:8]
        other_store = Store(
            merchant_id=other_merchant.id,
            store_code=f"HELPER_{unique_id.upper()}",
            subdomain=f"helper{unique_id.lower()}",
            name=f"Helper Test Store {unique_id}",
            is_active=True,
        )
        db.add(other_store)
        db.commit()

        with pytest.raises(ProductNotFoundException):
            self.service._get_store_product(
                db, other_store.id, test_product.id
            )

    def test_get_inventory_entry_returns_existing(
        self, db, test_inventory, test_product
    ):
        """Test _get_inventory_entry returns existing entry."""
        result = self.service._get_inventory_entry(
            db, test_product.id, test_inventory.bin_location
        )

        assert result is not None
        assert result.id == test_inventory.id

    def test_get_inventory_entry_returns_none(self, db, test_product):
        """Test _get_inventory_entry returns None when not found."""
        result = self.service._get_inventory_entry(
            db, test_product.id, "NONEXISTENT_LOCATION"
        )

        assert result is None

    def test_get_inventory_by_id_returns_existing(self, db, test_inventory):
        """Test _get_inventory_by_id returns existing entry."""
        result = self.service._get_inventory_by_id(db, test_inventory.id)

        assert result.id == test_inventory.id

    def test_get_inventory_by_id_raises_not_found(self, db):
        """Test _get_inventory_by_id raises when not found."""
        with pytest.raises(InventoryNotFoundException):
            self.service._get_inventory_by_id(db, 99999)
