"""Price-refresh task tests (logic-level, no broker)."""

from decimal import Decimal
from unittest.mock import patch

from django.test import TestCase

from shop.models import JITA_BUY_PCT, JITA_SELL_PCT, HullListing, Shop
from shop.tasks import _apply_prices_for_type, _enqueue_pct_refreshes
from shop.tests.test_stock import make_owner_character, make_ship_type


class ApplyPricesForTypeTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop_a = Shop.objects.create(slug="a", name="A", created_by=self.user)
        self.shop_b = Shop.objects.create(slug="b", name="B", created_by=self.user)

    def _listing(self, shop, mode=JITA_SELL_PCT, pct="90", price=0):
        return HullListing.objects.create(
            shop=shop, eve_type=self.ship, price_mode=mode,
            price_pct=Decimal(pct), price=price,
        )

    @patch("shop.tasks.jita_prices")
    def test_updates_all_shops_of_type(self, mock_jp):
        mock_jp.return_value = {"buy": 100, "sell": 200}
        la = self._listing(self.shop_a)   # 90% of sell 200 -> 180
        lb = self._listing(self.shop_b)
        _apply_prices_for_type(self.ship.id)
        la.refresh_from_db()
        lb.refresh_from_db()
        self.assertEqual(la.price, 180)
        self.assertEqual(lb.price, 180)

    @patch("shop.tasks.jita_prices")
    def test_keep_last_known_when_side_none(self, mock_jp):
        mock_jp.return_value = {"buy": None, "sell": None}
        la = self._listing(self.shop_a, price=42)
        _apply_prices_for_type(self.ship.id)
        la.refresh_from_db()
        self.assertEqual(la.price, 42)


class EnqueueDedupTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.ship2 = make_ship_type(type_id=672, name="Avatar")
        self.shop_a = Shop.objects.create(slug="a", name="A", created_by=self.user)
        self.shop_b = Shop.objects.create(slug="b", name="B", created_by=self.user)

    @patch("shop.tasks.refresh_price_for_type.apply_async")
    def test_one_task_per_distinct_type(self, mock_async):
        # same ship in two shops (pct) + a second ship (pct) + a fixed one (ignored)
        HullListing.objects.create(shop=self.shop_a, eve_type=self.ship, price_mode=JITA_BUY_PCT, price_pct=Decimal("95"))
        HullListing.objects.create(shop=self.shop_b, eve_type=self.ship, price_mode=JITA_SELL_PCT, price_pct=Decimal("90"))
        HullListing.objects.create(shop=self.shop_a, eve_type=self.ship2, price_mode=JITA_BUY_PCT, price_pct=Decimal("95"))
        HullListing.objects.create(shop=self.shop_b, eve_type=self.ship2)  # fixed -> ignored
        _enqueue_pct_refreshes()
        enqueued = sorted(call.kwargs["args"][0] for call in mock_async.call_args_list)
        self.assertEqual(enqueued, [self.ship.id, self.ship2.id])


from memberaudit.models import CharacterAsset, Location  # noqa: E402
from shop.models import AUTO_STOCK, FIXED_STOCK, HULL, ShopSource  # noqa: E402
from shop.tasks import _enqueue_stock_refreshes, _refresh_shop_stock  # noqa: E402


class RefreshShopStockTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.station = Location.objects.create(id=60003760, name="Jita IV-4")
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        ShopSource.objects.create(
            shop=self.shop, section=HULL, character=self.char, location=self.station
        )
        CharacterAsset.objects.create(
            character=self.char, item_id=1, eve_type=self.ship, is_singleton=True,
            location_flag="Hangar", quantity=4, location=self.station,
        )

    def test_recomputes_auto_listing(self):
        listing = HullListing.objects.create(
            shop=self.shop, eve_type=self.ship, stock_mode=AUTO_STOCK, stock=0
        )
        _refresh_shop_stock(self.shop.id)
        listing.refresh_from_db()
        self.assertEqual(listing.stock, 4)

    def test_leaves_fixed_listing(self):
        listing = HullListing.objects.create(
            shop=self.shop, eve_type=self.ship, stock_mode=FIXED_STOCK, stock=7
        )
        _refresh_shop_stock(self.shop.id)
        listing.refresh_from_db()
        self.assertEqual(listing.stock, 7)


class EnqueueStockRefreshesTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()

    @patch("shop.tasks.refresh_stock_for_shop.apply_async")
    def test_one_task_per_shop_with_auto_listing(self, mock_async):
        auto_shop = Shop.objects.create(slug="a", name="A", created_by=self.user)
        HullListing.objects.create(shop=auto_shop, eve_type=self.ship, stock_mode=AUTO_STOCK)
        fixed_shop = Shop.objects.create(slug="f", name="F", created_by=self.user)
        HullListing.objects.create(shop=fixed_shop, eve_type=self.ship, stock_mode=FIXED_STOCK)
        Shop.objects.create(slug="empty", name="E", created_by=self.user)  # no listings
        _enqueue_stock_refreshes()
        enqueued = sorted(call.kwargs["args"][0] for call in mock_async.call_args_list)
        self.assertEqual(enqueued, [auto_shop.id])
