"""Stock computation tests."""

from django.test import TestCase

from allianceauth.authentication.models import CharacterOwnership
from allianceauth.tests.auth_utils import AuthUtils
from eveuniverse.models import EveCategory, EveGroup, EveType
from memberaudit.models import Character, CharacterAsset, Location

from shop.models import AUTO_STOCK, FIXED_STOCK, HULL, HullListing, Shop, ShopSource
from shop.stock import recompute_shop_stock


def make_ship_type(type_id=671, name="Erebus", group_id=30, group_name="Titan",
                   category_id=6, category_name="Ship"):
    cat, _ = EveCategory.objects.get_or_create(id=category_id, defaults={"name": category_name, "published": True})
    grp, _ = EveGroup.objects.get_or_create(
        id=group_id, defaults={"name": group_name, "eve_category": cat, "published": True}
    )
    return EveType.objects.create(id=type_id, name=name, eve_group=grp, published=True)


def make_container_type(type_id=11488, name="Giant Secure Container", group_id=448):
    # Containers live outside the Ship category (use Celestial=2 for tests).
    return make_ship_type(type_id=type_id, name=name, group_id=group_id,
                          group_name="Cargo Container", category_id=2, category_name="Celestial")


def make_owner_character(username="owner", char_id=1001):
    user = AuthUtils.create_user(username)
    eve_char = AuthUtils.add_main_character_2(user, username, char_id, corp_id=2001, disconnect_signals=True)
    CharacterOwnership.objects.create(user=user, character=eve_char, owner_hash=f"oh-{char_id}")
    char = Character.objects.create(eve_character=eve_char)
    return user, char


class StockTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.station = Location.objects.create(id=60003760, name="Jita IV-4")
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        self.listing = HullListing.objects.create(shop=self.shop, eve_type=self.ship)

    def _asset(self, item_id, qty=1, location=None, parent=None, eve_type=None):
        return CharacterAsset.objects.create(
            character=self.char, item_id=item_id, eve_type=eve_type or self.ship,
            is_singleton=True, location_flag="Hangar", quantity=qty,
            location=location, parent=parent,
        )

    def test_station_hangar_stock(self):
        self._asset(1, location=self.station)
        self._asset(2, location=self.station)
        ShopSource.objects.create(shop=self.shop, section=HULL, character=self.char, location=self.station)
        self.assertEqual(self.listing.recompute_stock(), 2)

    def test_container_stock(self):
        container_type = make_container_type()
        container = self._asset(500, location=self.station, eve_type=container_type)
        self._asset(3, parent=container)
        self._asset(4, parent=container)
        ShopSource.objects.create(
            shop=self.shop, section=HULL, character=self.char, location=self.station, container_item_id=500
        )
        self.assertEqual(self.listing.recompute_stock(), 2)

    def test_multiple_sources_summed(self):
        station2 = Location.objects.create(id=60003761, name="Amarr")
        self._asset(1, location=self.station)
        self._asset(2, location=station2)
        ShopSource.objects.create(shop=self.shop, section=HULL, character=self.char, location=self.station)
        ShopSource.objects.create(shop=self.shop, section=HULL, character=self.char, location=station2)
        self.assertEqual(self.listing.recompute_stock(), 2)

    def test_zero_when_no_assets(self):
        ShopSource.objects.create(shop=self.shop, section=HULL, character=self.char, location=self.station)
        self.assertEqual(self.listing.recompute_stock(), 0)


class PersistRemovalTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.station = Location.objects.create(id=60003760, name="Jita IV-4")
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        # A stockroom exists but holds no assets of this ship -> stock recomputes to 0.
        ShopSource.objects.create(
            shop=self.shop, section=HULL, character=self.char, location=self.station
        )

    def _listing(self, **kw):
        return HullListing.objects.create(shop=self.shop, eve_type=self.ship, **kw)

    def test_non_persist_auto_stock_at_zero_is_removed(self):
        listing = self._listing(stock_mode=AUTO_STOCK, persist=False)
        recompute_shop_stock(self.shop)
        self.assertFalse(HullListing.objects.filter(pk=listing.pk).exists())

    def test_persist_auto_stock_at_zero_is_kept(self):
        listing = self._listing(stock_mode=AUTO_STOCK, persist=True)
        recompute_shop_stock(self.shop)
        self.assertTrue(HullListing.objects.filter(pk=listing.pk).exists())

    def test_auto_stock_with_stock_is_kept(self):
        CharacterAsset.objects.create(
            character=self.char, item_id=1, eve_type=self.ship,
            is_singleton=True, location_flag="Hangar", quantity=1,
            location=self.station, parent=None,
        )
        listing = self._listing(stock_mode=AUTO_STOCK, persist=False)
        recompute_shop_stock(self.shop)
        self.assertTrue(HullListing.objects.filter(pk=listing.pk).exists())

    def test_fixed_stock_at_zero_is_kept_even_when_not_persist(self):
        listing = self._listing(stock_mode=FIXED_STOCK, stock=0, persist=False)
        recompute_shop_stock(self.shop)
        self.assertTrue(HullListing.objects.filter(pk=listing.pk).exists())
