"""
inventory/tests/test_models.py
Tests for inventory model behaviour and properties.
"""

from datetime import date
from decimal import Decimal

from django.contrib.auth import get_user_model
from django.test import TestCase

from catalog_app.models import Author, Book
from inventory.models import (
    AuthorPayout,
    InventoryBalance,
    InventoryTransaction,
    Sale,
    SaleItem,
    StockLocation,
)

User = get_user_model()


def make_author(**kwargs):
    defaults = {"name": "Test Author", "default_my_keep_percent": Decimal("25.00"), "default_author_pay_percent": Decimal("75.00")}
    defaults.update(kwargs)
    return Author.objects.create(**defaults)


def make_book(author, **kwargs):
    defaults = {
        "title": "Test Book",
        "author": author,
        "price": Decimal("1500.00"),
        "my_keep_percent": Decimal("25.00"),
        "reorder_level": 5,
        "track_inventory": True,
        "is_listed": True,
    }
    defaults.update(kwargs)
    return Book.objects.create(**defaults)


def make_location(**kwargs):
    defaults = {"name": "Main Warehouse", "code": "WH001", "location_type": StockLocation.TYPE_WAREHOUSE}
    defaults.update(kwargs)
    return StockLocation.objects.create(**defaults)


class StockLocationModelTest(TestCase):
    def test_str(self):
        loc = make_location()
        self.assertIn("WH001", str(loc))

    def test_default_is_active(self):
        loc = make_location(code="WH002")
        self.assertTrue(loc.is_active)


class InventoryBalanceModelTest(TestCase):
    def setUp(self):
        self.author = make_author()
        self.book = make_book(self.author)
        self.location = make_location()

    def test_quantity_available_no_reservation(self):
        balance = InventoryBalance.objects.create(
            book=self.book, location=self.location,
            quantity_on_hand=20, quantity_reserved=0,
        )
        self.assertEqual(balance.quantity_available, 20)

    def test_quantity_available_with_reservation(self):
        balance = InventoryBalance.objects.create(
            book=self.book, location=self.location,
            quantity_on_hand=10, quantity_reserved=4,
        )
        self.assertEqual(balance.quantity_available, 6)

    def test_quantity_available_never_negative(self):
        balance = InventoryBalance.objects.create(
            book=self.book, location=self.location,
            quantity_on_hand=3, quantity_reserved=10,
        )
        self.assertEqual(balance.quantity_available, 0)


class SaleModelTest(TestCase):
    def test_invoice_number_format(self):
        author = make_author()
        book = make_book(author)
        user = User.objects.create_user(username="testuser", password="pass")
        sale = Sale.objects.create(
            sale_channel=Sale.CHANNEL_DIRECT,
            sale_date=date.today(),
            recorded_by=user,
        )
        self.assertTrue(sale.invoice_number.startswith("INV-"))

    def test_invoice_number_unique(self):
        author = make_author()
        book = make_book(author)
        user = User.objects.create_user(username="testuser2", password="pass")
        sale1 = Sale.objects.create(sale_channel=Sale.CHANNEL_DIRECT, sale_date=date.today(), recorded_by=user)
        sale2 = Sale.objects.create(sale_channel=Sale.CHANNEL_DIRECT, sale_date=date.today(), recorded_by=user)
        self.assertNotEqual(sale1.invoice_number, sale2.invoice_number)


class AuthorPayoutModelTest(TestCase):
    def test_outstanding_balance_property(self):
        author = make_author()
        payout = AuthorPayout.objects.create(
            author=author,
            period_type=AuthorPayout.PERIOD_MONTHLY,
            period_start=date(2025, 1, 1),
            period_end=date(2025, 1, 31),
            total_earnings=Decimal("5000.00"),
            total_paid=Decimal("3000.00"),
        )
        self.assertEqual(payout.outstanding_balance, Decimal("2000.00"))
